Rex W. Douglass

Introduction

Library Loads

#libraries
library(lubridate)
library(tidyverse)

#devtools::install_github("ropensci/USAboundaries")

#devtools::install_github("ropensci/USAboundariesData")
library(USAboundaries) ; #install.packages('USAboundaries')
data(state_codes)

library(tidyverse)
library(scales)
library(gghighlight)
library(lubridate)
library(R0)  # consider moving all library commands to top -- this one was in a loop below

library(WikidataR)
library(countrycode)

library(usmap) ; # install.packages('usmap')
data(statepop)
#devtools::install_github("ropensci/USAboundaries")
#devtools::install_github("ropensci/USAboundariesData")
library(USAboundaries) ; #install.packages('USAboundaries')
data(state_codes)

library(tidyverse)
library(sf)

library(jsonlite)

#This is too slow it's downloading each
library(GADMTools)
library(strucchange) ; #install.packages('strucchange')
library(tsibble)

Data Loading and Cleaning


library(patchwork)


library(tsibble)

lhs_long <- readRDS("/media/skynet2/905884f0-7546-4273-9061-12a790830beb/rwd_github_private/NESScovid19/data_temp/lhs_long.Rds")
#dim(lhs_long) #187,305

lhs_long_clean <- lhs_long %>% 
                  dplyr::select(dataset, gid,geonameid, wikidata_id ,date_asdate, confirmed, deaths, tested_people, tested_samples) %>%
                  group_by(dataset, gid,geonameid, wikidata_id ,date_asdate) %>% #if the same source has multiple values on the same thing on the same day, or different values across unmerged obs, then take the max
                  summarise_all(max, na.rm=T) %>% 
                  ungroup() %>%
                  mutate_if(is.numeric, list(~na_if(., -Inf))) %>%
                  mutate_if(is.numeric, list(~na_if(., Inf))) %>%
                  mutate(dataset_gid_geonameid_wikidata_id= paste(dataset,gid,geonameid, wikidata_id, sep="_")  ) %>%
                  mutate(gid_geonameid_wikidata_id= paste(gid,geonameid, wikidata_id, sep="_")  ) %>%
  
                  filter(!is.na(date_asdate)) %>%
                  
                  #First drop anything that's negative. Shouldn't be any negatives.
                  filter(is.na(confirmed) | confirmed>=0) %>%
                  filter(is.na(deaths) | deaths>=0) %>%
                  filter(is.na(tested_people) | tested_people>=0) %>%
                  filter(is.na(tested_samples) | tested_samples>=0) %>%
                  
                  #Then set 0s to NA, we don't trust NAs
                  mutate(confirmed=ifelse(confirmed==0, NA, confirmed)) %>%
                  mutate(deaths=ifelse(deaths==0, NA, deaths)) %>%
                  mutate(tested_people=ifelse(tested_people==0, NA, tested_people)) %>%
                  mutate(tested_samples=ifelse(tested_samples==0, NA, tested_samples)) %>%
                
                  #Then check first differences and drop anything that doesn't weakly increase monotonically
                  group_by(dataset, gid_geonameid_wikidata_id) %>% 
                    arrange(date_asdate) %>%
                    mutate(confirmed_cummax=confirmed %>% replace_na(0) %>% 
                             cummax(), deaths_cummax=deaths%>% replace_na(0) %>% cummax(), tested_people_cummax=tested_people%>% replace_na(0) %>% cummax(), 
                             tested_samples_cummax=tested_samples%>% replace_na(0) %>% cummax()) %>%
                  ungroup() %>%  
  
                  #About 4k of these observations show a decrease from one time step to the next which suggests either an original error or a joining error
                  #We're going to straight drop those observations as a cleaning step
                  #this isn't enough because if you have consecutive mistakes it'll show a positive fd even if it's not good enough
                  filter( (is.na(confirmed) | confirmed>=confirmed_cummax) &  #never allow for a reversal
                          (is.na(deaths) | deaths>=deaths_cummax) &        #never allow for a reversal
                          (is.na(tested_people) | tested_people>=tested_people_cummax) &  #never allow for a reversal
                          (is.na(tested_samples) | tested_samples>=tested_samples_cummax)  #never allow for a reversal
                          ) %>%
  #we're going to go one step further and require either confirmed or tested to be strictly higher
  #In words, during an episode we don't believe reports mean "no new cases" just no new good reporting
  #metabiota is the worst offender here so restricting it to just that
  filter( !(
            dataset=="metabiota" & #is metabiota
            (!is.na(confirmed) &   #with a non missing confirmed
              confirmed<=confirmed_cummax ) #that is equal to or less than the cumulative max until then.
            ) #reject these
          ) %>% #metabiota is really problematic 90% of what we're doing is trying to account for it
  
  #Also reject any where deaths are greater than confirmed
  filter(is.na(confirmed) | is.na(deaths) | confirmed>=deaths) %>%
  
  #also reject any where confirmed doesn't vary 
  group_by(gid ,  geonameid ,wikidata_id) %>% #chose not to do by dataset because testing datasets might not have confirmed
    filter(var(confirmed, na.rm=T)>0) %>%
  ungroup()

  
#dim(lhs_long_clean) #281,464 #292,580 #299213 #181,563

saveRDS(lhs_long_clean,
        "/media/skynet2/905884f0-7546-4273-9061-12a790830beb/rwd_github_private/NESScovid19/data_temp/lhs_long_cleand.Rds")

Summary Statistics of Our Data

print("Number of observations")
[1] "Number of observations"
dim(lhs_long_clean)
[1] 615638     15
print("Number of locations")
[1] "Number of locations"
lhs_long_clean$wikidata_id %>% unique() %>% length() #3,373
[1] 4263
print("Number of Days")
[1] "Number of Days"
lhs_long_clean$date_asdate %>% unique() %>% length() #113
[1] 128
library(DT) #https://rstudio.github.io/DT/
lhs_long_clean %>% count(dataset) %>% arrange(-n) %>% DT::datatable(options = list(pageLength = 20, autoWidth = TRUE))


#library(gt)
#lhs_long_clean %>% count(dataset) %>% arrange(-n) %>% gt() %>% 
# tab_header(
#    title = md("Location-Days by Dataset")#,
#    #subtitle = "Number of Days with Data by Dataset"
#  ) %>%
#  fmt_missing( columns=everything(), rows=NULL,missing_text = 0)

Spatial Variation in Data Availability

Country Level Data Availability


#gadm36 = st_read("/media/skynet2/905884f0-7546-4273-9061-12a790830beb/rwd_github_private/NESSgadm/data_in/gadm36_gpkg/gadm36.gpkg")
#st_layers("/media/skynet2/905884f0-7546-4273-9061-12a790830beb/rwd_github_private/NESScovid19/data_temp/gadm36_bycountry/gadm36_levels_gpkg/gadm36_levels.gpkg")
gadm36_levels_0 = st_read("/media/skynet2/905884f0-7546-4273-9061-12a790830beb/rwd_github_private/NESScovid19/data_temp/gadm36_bycountry/gadm36_levels_gpkg/gadm36_levels.gpkg", layer="level0")  %>%
                  st_simplify(preserveTopology = FALSE, dTolerance =0.1) #  0.025 this is supposedly broken up by 6 levels and so should have u.s. 
#plot(gadm36_levels_0)
#dim(gadm36_levels_0_sf$sf)
#gadm_plot(gadm36_levels_0_sf)
lhs_long_place_sources <- lhs_long  %>% dplyr::select(gid,   geonameid, wikidata_id, dataset) %>% 
                           group_by(gid,  geonameid, wikidata_id) %>% count(dataset) %>%
                           group_by(gid,  geonameid, wikidata_id) %>%
                           summarise(datasets_n=n()) 

p0 <- gadm36_levels_0 %>% 
      left_join(lhs_long_place_sources %>% dplyr::select(gid=gid, datasets_n) %>%  left_join( gadm36_levels_0 %>% as.data.frame() %>% dplyr::select(gid=GID_0, NAME_0)  %>% distinct()  )
                ) %>%
      #replace_na(list(datasets_n = 0)) %>% 
      ggplot() + geom_sf(aes(fill = datasets_n)) +
      scale_fill_gradient(low="red", high="green") +
      theme_bw() 
p0 + ggtitle("Covid Count Data Availability at the Country Level")

temp <- gadm36_levels_0 %>%
   left_join(
   lhs_long  %>% count(gid, dataset) %>% rename(GID_0=gid) #there are still dupe geonames wikidata to gid matches that need to be fixed geonameid, wikidata_id, 
) 
Joining, by = "GID_0"
Column `GID_0` joining factor and character vector, coercing into character vector
temp_wide <- temp %>% as.data.frame() %>% dplyr::select(Country=NAME_0, dataset, n) %>% distinct() %>% pivot_wider( id_cols = Country, names_from = dataset,
  values_from = n, values_fill = NULL, values_fn = NULL) 

temp_wide %>% DT::datatable(options = list(pageLength = 20, autoWidth = TRUE))


#install.packages('gt')
#library(gt)
#temp_wide %>% gt() %>% 
# tab_header(
#    title = md("Data Availability by Country"),
#    subtitle = "Number of Days with Data by Dataset"
#  ) %>%
#  fmt_missing( columns=everything(), rows=NULL,missing_text = 0)

State/Province Level Data Availability

gadm36_levels_1 = st_read("/media/skynet2/905884f0-7546-4273-9061-12a790830beb/rwd_github_private/NESScovid19/data_temp/gadm36_bycountry/gadm36_levels_gpkg/gadm36_levels.gpkg", layer="level1")  %>%
  st_simplify(preserveTopology = FALSE, dTolerance =0.1) #  0.025 this is supposedly broken up by 6 levels and so should have u.s. 
p1 <- gadm36_levels_1 %>% 
  left_join(lhs_long_place_sources %>% dplyr::select(gid=gid, datasets_n) %>%  left_join( gadm36_levels_1 %>% as.data.frame() %>% dplyr::select(gid=GID_1, NAME_1) %>% distinct()  )
  ) %>%
  #replace_na(list(datasets_n = 0)) %>% 
  ggplot() + geom_sf(aes(fill = datasets_n)) +
  scale_fill_gradient(low="red", high="green") +
  theme_bw() 
p1

temp <- gadm36_levels_1 %>%
   left_join(
   lhs_long  %>% count(gid, dataset) %>% rename(GID_1=gid) #there are still dupe geonames wikidata to gid matches that need to be fixed geonameid, wikidata_id, 
) 
Joining, by = "GID_1"
Column `GID_1` joining factor and character vector, coercing into character vector
temp_wide <- temp %>% as.data.frame() %>% dplyr::select(Country=NAME_0, Admin1=NAME_1, dataset, n) %>% distinct() %>% pivot_wider( id_cols = Country:Admin1, names_from = dataset,
  values_from = n, values_fill = NULL, values_fn = NULL) %>% mutate(total = rowSums(.[-c(1,2)], na.rm = T))

temp_wide %>% filter(total>0) %>% DT::datatable(options = list(pageLength = 10, autoWidth = TRUE))

NA

County District Level Data Availability

gadm36_levels_2 = st_read("/media/skynet2/905884f0-7546-4273-9061-12a790830beb/rwd_github_private/NESScovid19/data_temp/gadm36_bycountry/gadm36_levels_gpkg/gadm36_levels.gpkg", layer="level2")  %>%
  st_simplify(preserveTopology = FALSE, dTolerance = 0.001) #  0.025 this is supposedly broken up by 6 levels and so should have u.s. I have to keep shrinking it so misisng goes to zero 
p2 <- gadm36_levels_2 %>% 
  left_join(lhs_long_place_sources %>% dplyr::select(gid=gid, datasets_n) %>%  left_join( gadm36_levels_2 %>% as.data.frame() %>% dplyr::select(gid=GID_2, NAME_2) %>% distinct()  )
  ) %>%
  #replace_na(list(datasets_n = 0)) %>% 
  ggplot() + geom_sf(aes(fill = datasets_n),lwd = 0) +
  scale_fill_gradient(low="blue", high="red") +
  theme_bw() 
p2
temp <- gadm36_levels_2 %>%
   left_join(
   lhs_long  %>% count(gid, dataset) %>% rename(GID_2=gid) #there are still dupe geonames wikidata to gid matches that need to be fixed geonameid, wikidata_id, 
) 
Joining, by = "GID_2"
Column `GID_2` joining factor and character vector, coercing into character vector
temp_wide <- temp %>% as.data.frame() %>% dplyr::select(Country=NAME_0, Admin1=NAME_1, Admin2=NAME_2, dataset, n) %>% distinct() %>% pivot_wider( id_cols = Country:Admin2, names_from = dataset,
  values_from = n, values_fill = NULL, values_fn = NULL) %>% mutate(total = rowSums(.[-c(1,2,3)], na.rm = T))

temp_wide %>% filter(total>0) %>% DT::datatable(options = list(pageLength = 10, autoWidth = TRUE))
It seems your data is too big for client-side DataTables. You may consider server-side processing: https://rstudio.github.io/DT/server.htmlIt seems your data is too big for client-side DataTables. You may consider server-side processing: https://rstudio.github.io/DT/server.html

Country Data Availability of Testing


lhs_long_place_sources_testing <- lhs_long  %>%
                                  dplyr::select(gid,  geonameid, wikidata_id, date_asdate, confirmed, tested_people, tested_samples) %>%
                                  group_by(gid,  geonameid, wikidata_id, date_asdate) %>% 
                                  mutate_if(is.numeric, max, na.rm=T) %>%
                                  filter(!duplicated(date_asdate)) %>%
                                  ungroup() %>%
                                  mutate_if(is.numeric, list(~na_if(., -Inf))) %>%
                                  mutate_if(is.numeric, list(~na_if(., Inf))) %>%
                                  mutate(percent_of_days_without_testing=!is.na(date_asdate) & (is.na(tested_people) & is.na(tested_samples)  )) %>%
                                  
                                  group_by(gid,  geonameid, wikidata_id) %>% 
                                  summarise(
                                            percent_of_days_without_testing=sum(percent_of_days_without_testing, na.rm=T)/n()
                                            ) %>%
                                  mutate(percent_of_days_with_testing= 1-percent_of_days_without_testing) 
`mutate_if()` ignored the following grouping variables:
Columns `gid`, `geonameid`, `wikidata_id`, `date_asdate`
p0_testing <- gadm36_levels_0 %>% 
      left_join(lhs_long_place_sources_testing %>% dplyr::select(gid=gid, percent_of_days_with_testing) %>%  left_join( gadm36_levels_0 %>% as.data.frame() %>% dplyr::select(gid=GID_0, NAME_0)  %>% distinct()  )
                ) %>%
      #replace_na(list(datasets_n = 0)) %>% 
      ggplot() + geom_sf(aes(fill = percent_of_days_with_testing)) +
      scale_fill_gradient(low="red", high="green") +
      theme_bw() + ggtitle("Percent of Days with Testing counts")
Adding missing grouping variables: `geonameid`
Joining, by = "gid"
Column `gid` joining character vector and factor, coercing into character vectorJoining, by = "NAME_0"
p0_testing

p1_testing <- gadm36_levels_1 %>% 
  left_join(lhs_long_place_sources_testing %>% dplyr::select(gid=gid, percent_of_days_with_testing) %>%  left_join( gadm36_levels_1 %>% as.data.frame() %>% dplyr::select(gid=GID_1, NAME_1) %>% distinct()  )
  ) %>%
  #replace_na(list(datasets_n = 0)) %>% 
  ggplot() + geom_sf(aes(fill = percent_of_days_with_testing)) +
  scale_fill_gradient(low="red", high="green") +
  theme_bw()  + ggtitle("Percent of Days with Testing counts")
p1_testing

Data Availability and Interpolation over Time


#test <- lhs_long %>% group_by(dataset, gid, geonameid, wikidata_id, date_asdate) %>% summarize(n=n())

all_na <- function(x) any(!is.na(x)) #https://intellipaat.com/community/12999/remove-columns-from-dataframe-where-all-values-are-na

#bing looks off by a day from the other ones
lhs_wide_qcode <- lhs_long %>% 
                  filter(!is.na(wikidata_id) & !is.na(date_asdate)) %>%
                  group_by(gid, geonameid, wikidata_id, date_asdate) %>%  mutate(confirmed_var=var(confirmed, na.rm=T), deaths_var=var(deaths, na.rm=T)) %>% ungroup() %>%
                  dplyr::select(dataset, gid, geonameid, wikidata_id, date_asdate,confirmed, deaths, tested_samples, tested_people) %>%
                  group_by(dataset, gid, geonameid, wikidata_id, date_asdate) %>%  summarise_if(is.numeric,max,na.rm=T) %>% ungroup() %>% #this is a hack, we should have dupes within datasets
                  pivot_wider(names_from = dataset, values_from = c(confirmed, deaths, tested_samples, tested_people) ) %>% 
                  mutate_if(is.numeric, list(~na_if(abs(.), Inf))) %>% #https://stackoverflow.com/questions/12188509/cleaning-inf-values-from-an-r-dataframe
                  select_if(all_na) 

dim(lhs_wide_qcode) #82,157 82k place/day observations
length(unique(lhs_wide_qcode$wikidata_id)) #3697 #almost 4k 
test <- lhs_wide_qcode %>% dplyr::select(starts_with("confirmed")) %>% distinct() 
#cor(test, use="pairwise.complete.obs")

lhs_long_median <- lhs_long %>% group_by(gid, geonameid, wikidata_id, date_asdate) %>% summarize_if(is.numeric, median, na.rm=T) %>% dplyr::select(-ends_with("_fd")) %>% #we take the median across observations
                   mutate(CFR=deaths/confirmed)
#dim(lhs_long_median)
#summary(lhs_long_median)

Here we do the actual interpolation. For each individual location-dataset, we fit a piecewise linear model over time, and then use that to average over day to day noise and interpolate between observations. Because this is in log space, the slope of that line is the day on day percent increase in the count. We finish by fitting a piecewise intercept model to those slopes to get a single daily estimate of how much the count is increasing. Datasets are able to disagree in lots of different ways and we still recover a correct rate of change.

Interpolation of Counts

To each individual dataset-location series, we fit a piecewise linear trend. Each segment is required to have at least 3 observations, but otherwise we make no other constraints. This allows us to flexibly fit linear segments as well as tight curves. We also allow for structural breaks where the series stops, has a structural shift up or down because say a change in reporting rules, but other then otherwise continues as normal. We take the linear trend fit as our best estimate at each point. This averages over day to day noise, e.g. under reporting on the weekend. It also allows us to interpolate between observations where there is missingness in the series but we have reasonable beliefs the true measure continued linearly between the observed points.


#we need to parallelize this code and see what's loudly throwing
#Error in chol.default(J12) : 
#  the leading minor of order 1 is not positive definite

dataset_places <- lhs_long_clean %>% dplyr::select(dataset_gid_geonameid_wikidata_id) %>% distinct() %>% pull(dataset_gid_geonameid_wikidata_id)
library(party)
temp_list1 <- list()
options(error = expression(NULL))
sink(NULL)
zz <- file("messages.txt", open = "wt")
sink(zz)
suppressMessages(
for(q in dataset_places  ){
      #try({
        temp <- NULL
        temp <- lhs_long_clean %>%
                filter(dataset_gid_geonameid_wikidata_id %in% q) %>%
                arrange(date_asdate) %>%

                mutate(confirmed_log=log(confirmed)) %>%
                mutate(deaths_log=log(deaths)) %>%
                mutate(tested_people_log=log(tested_people)) %>%
                mutate(tested_samples_log=log(tested_samples)) 
          
        if(nrow(temp)==0){next()}
        
        temp <- temp %>% expand(dataset, gid_geonameid_wikidata_id, gid, geonameid,wikidata_id, date_asdate=min(date_asdate):max(date_asdate) %>% as_date() ) %>% 
                 full_join(temp) %>% 
                 mutate(date_asnumeric= as.numeric(date_asdate) ) %>% 
                 arrange(date_asnumeric) %>%
                 mutate(confirmed_nonmissing_count     = (!is.na(confirmed)) %>% cumsum() ) %>%
                 mutate(deaths_nonmissing_count     = (!is.na(deaths)) %>% cumsum() ) %>%
                 mutate(tested_people_nonmissing_count     = (!is.na(tested_people)) %>% cumsum() ) %>%
                 mutate(tested_samples_nonmissing_count     = (!is.na(tested_samples)) %>% cumsum() ) %>%
        
                 arrange(-date_asnumeric) %>%
                 mutate(confirmed_nonmissing_count_reversed     = (!is.na(confirmed)) %>% cumsum() ) %>%
                 mutate(deaths_nonmissing_count_reversed     = (!is.na(deaths)) %>% cumsum() ) %>%
                 mutate(tested_people_nonmissing_count_reversed     = (!is.na(tested_people)) %>% cumsum() ) %>%
                 mutate(tested_samples_nonmissing_count_reversed     = (!is.na(tested_samples)) %>% cumsum() ) %>% 
                 arrange(date_asdate) 

        tryCatch({  
          if(sum(!is.na(temp$confirmed_log))>=3){ #need at least 3 points
            tree_confirmed <- party::mob(confirmed_log ~ 1 + date_asnumeric    | date_asnumeric , control = mob_control(minsplit = 3, alpha=.2), data = temp,  model = linearModel)  # + I(date_asnumeric^2)  
            temp$confirmed_log_y_hat <- predict( tree_confirmed, newdata=temp , type = c("response") )
            temp$confirmed_log_group_number <-  predict( tree_confirmed, newdata=temp , type = c("node"))
            temp <- temp %>% 
                    mutate(confirmed_log_y_hat       =ifelse(confirmed_nonmissing_count>0 & confirmed_nonmissing_count_reversed>0,confirmed_log_y_hat,NA)) %>% #only interpolate within the observed data, never before or after
                    mutate(confirmed_log_group_number=ifelse(confirmed_nonmissing_count>0 & confirmed_nonmissing_count_reversed>0,confirmed_log_group_number,NA)) %>% #only interpolate within the observed data, never before or after

                    group_by(confirmed_log_group_number) %>%
                    arrange(date_asnumeric) %>%
                    mutate(confirmed_log_y_hat_slope=tsibble::difference(confirmed_log_y_hat)) %>% 
                    fill(confirmed_log_y_hat_slope, .direction="up") %>% 
                    ungroup() %>%
                    mutate(confirmed_log_y_hat_percent_change = round((exp(confirmed_log_y_hat_slope)-1)*100,2))  %>%
                    mutate(confirmed_log_y_hat=ifelse(confirmed_log_y_hat<0,NA, confirmed_log_y_hat))
          }
        }, error = function(e) {}, silent=TRUE)
        
        tryCatch({  
          if(sum(!is.na(temp$deaths_log))>=3){ #need at least 3 points
            tree_deaths <- party::mob(deaths_log ~ 1 + date_asnumeric    | date_asnumeric , control = mob_control(minsplit = 3, alpha=.2), data = temp,  model = linearModel)  # + I(date_asnumeric^2)    
            temp$deaths_log_y_hat <- predict( tree_deaths, newdata=temp , type = c("response") )
            temp$deaths_log_group_number <-  predict( tree_deaths, newdata=temp , type = c("node"))
            temp <- temp %>% 
                    mutate(deaths_log_y_hat=ifelse(deaths_nonmissing_count>0 & deaths_nonmissing_count_reversed>0,deaths_log_y_hat,NA)) %>% #only interpolate within the observed data, never before
                    mutate(deaths_log_group_number=ifelse(deaths_nonmissing_count>0 & deaths_nonmissing_count_reversed>0,deaths_log_group_number,NA)) %>% #only interpolate within the observed data, never before

                    group_by(deaths_log_group_number) %>% 
                    arrange(date_asnumeric) %>% 
                    mutate(deaths_log_y_hat_slope=tsibble::difference(deaths_log_y_hat)) %>%
                    fill(deaths_log_y_hat_slope, .direction="up") %>%
                    ungroup() %>%
                    mutate(deaths_log_y_hat_percent_change = round((exp(deaths_log_y_hat_slope)-1)*100,2)) %>%
                    mutate(deaths_log_y_hat=ifelse(deaths_log_y_hat<0,NA, deaths_log_y_hat)) #reject any where the prediction is less than 1 full case
          }
        }, error = function(e) {}, silent=TRUE)
        
        tryCatch({  
          if(sum(!is.na(temp$tested_people_log))>=3){ #need at least 3 points
            tree_tested_people <- party::mob(tested_people_log ~ 1 + date_asnumeric    | date_asnumeric , control = mob_control(minsplit = 3, alpha=.2), data = temp,  model = linearModel)  # + I(date_asnumeric^2)   
            temp$tested_people_log_y_hat <- predict( tree_tested_people, newdata=temp , type = c("response") )
            temp$tested_people_log_group_number <-  predict( tree_tested_people, newdata=temp , type = c("node"))
            temp <- temp %>% 
                       mutate(tested_people_log_y_hat=ifelse(tested_people_nonmissing_count>0 & tested_people_nonmissing_count_reversed>0,tested_people_log_y_hat,NA)) %>% #only interpolate within the observed data, never before
                       mutate(tested_people_log_group_number=ifelse(tested_people_nonmissing_count>0 & tested_people_nonmissing_count_reversed>0,tested_people_log_group_number,NA)) %>% #only interpolate within the observed data, never before
              
                       group_by(tested_people_log_group_number) %>% 
                       arrange(date_asnumeric) %>%
                       mutate(tested_people_log_y_hat_slope=tsibble::difference(tested_people_log_y_hat)) %>% 
                       fill(tested_people_log_y_hat_slope, .direction="up") %>% ungroup() %>%
                       mutate(tested_people_log_y_hat_percent_change = round((exp(tested_people_log_y_hat_slope)-1)*100,2)) %>%
                       mutate(tested_people_log_y_hat=ifelse(tested_people_log_y_hat<0,NA, tested_people_log_y_hat)) #reject any where the prediction is less than 1 full case
          }
        }, error = function(e) {}, silent=TRUE)
        
        temp_list1[[q ]] <- temp
  
      #})
}
)
sink(NULL)
lhs_long_clean_imputed1 <- bind_rows(temp_list1)
dim(lhs_long_clean_imputed1) #500,786 #bigger because we're interpolating now

#rt1 <- rpart(formula = confirmed_log_y_hat_percent_change ~ date_asnumeric, data=test)
#interpolated = data.frame(date_asnumeric=min(test$date_asnumeric):max(test$date_asnumeric) )
#interpolated$confirmed_log_y_hat_percent_change_y_hat <-  predict(rt1, newdata=interpolated)
#interpolated$date_asdate <- as.Date(interpolated$date_asnumeric)

places <- lhs_long_clean %>% dplyr::select(gid_geonameid_wikidata_id) %>% distinct() %>% pull(gid_geonameid_wikidata_id)

library(rpart)
minsplit=6
minbucket=3
temp_list2 <- list()
for(q in places ){
  print(q)
  temp <- lhs_long_clean_imputed1 %>% 
                 filter(gid_geonameid_wikidata_id %in% q) %>% 
                 arrange(date_asnumeric) 
    
          
  tryCatch({  
    rt1 <- rpart::rpart(formula = confirmed_log_y_hat_percent_change ~ date_asnumeric,
                        data=temp %>% filter(!is.na(confirmed_log)), #to keep from fitting to interpolate slopes that are out of domain and usually wrong, require confirmed to not be missing or na
                        control = rpart.control(minsplit = minsplit, minbucket=minbucket))
    temp$confirmed_log_y_hat_percent_change_y_hat <-  predict(rt1, newdata=temp) #this prediction helpfully tries to impute backwards even before there are any day in any series
    #We need to nuke it if no data exist
    temp <- temp %>%
            group_by(date_asdate) %>%
            mutate( confirmed_nonmissing_count_datasets=sum(confirmed_nonmissing_count>0,na.rm=T) ) %>%
            mutate( confirmed_nonmissing_count_datasets_reversed=sum(confirmed_nonmissing_count_reversed>0,na.rm=T) ) %>%
            mutate(confirmed_log_y_hat_percent_change_y_hat=ifelse(confirmed_nonmissing_count_datasets>0 & confirmed_nonmissing_count_datasets_reversed>0,confirmed_log_y_hat_percent_change_y_hat,NA))  %>%
      ungroup()
    
  }, error = function(e) {})
  
  tryCatch({  
    rt2 <- rpart::rpart(formula = deaths_log_y_hat_percent_change ~ date_asnumeric,
                        data=temp %>% filter(!is.na(deaths_log)),
                        control = rpart.control(minsplit = minsplit, minbucket=minbucket))
    temp$deaths_log_y_hat_percent_change_y_hat <-  predict(rt2, newdata=temp)
    temp <- temp %>%
        group_by(date_asdate) %>%
        mutate( deaths_nonmissing_count_datasets=sum(deaths_nonmissing_count>0,na.rm=T) ) %>%
        mutate( deaths_nonmissing_count_datasets_reversed=sum(deaths_nonmissing_count_reversed>0,na.rm=T) ) %>%
        mutate(deaths_log_y_hat_percent_change_y_hat=ifelse(deaths_nonmissing_count_datasets>0 & deaths_nonmissing_count_datasets_reversed>0,deaths_log_y_hat_percent_change_y_hat,NA)) %>%
      ungroup()
        
  }, error = function(e) {})

  tryCatch({  
    rt3 <- rpart::rpart(formula = tested_people_log_y_hat_percent_change ~ date_asnumeric,
                    data=temp %>% filter(!is.na(tested_people_log)),
                    control = rpart.control(minsplit = minsplit, minbucket=minbucket))
    temp$tested_people_log_y_hat_percent_change_y_hat <-  predict(rt3, newdata=temp, control = rpart.control(minsplit = minsplit, minbucket=minbucket))
    temp <- temp %>%
        group_by(date_asdate) %>%
        mutate( tested_people_nonmissing_count_datasets=sum(tested_people_nonmissing_count>0,na.rm=T) ) %>%
        mutate( tested_people_nonmissing_count_datasets_reversed=sum(tested_people_nonmissing_count_reversed>0,na.rm=T) ) %>%
      
        mutate(tested_people_log_y_hat_percent_change_y_hat=ifelse(tested_people_nonmissing_count_datasets>0 & tested_people_nonmissing_count_datasets_reversed>0,tested_people_log_y_hat_percent_change_y_hat,NA))  %>%
      ungroup()
  }, error = function(e) {})
  
  temp_list2[[q ]] <- temp
}
lhs_long_clean_imputed2 <- bind_rows(temp_list2)

lhs_long_clean_imputed <- lhs_long_clean_imputed2
dim(lhs_long_clean_imputed) #629,493 #419910 #413475 #408,369 #we lose anywithout q codes here
saveRDS(lhs_long_clean_imputed, "/media/skynet2/905884f0-7546-4273-9061-12a790830beb/rwd_github_private/NESScovid19/data_temp/lhs_long_clean_imputed.Rds")

Examples

China

#China
#"Q148"

test <- lhs_long_clean_imputed %>% 
        mutate(group=paste(dataset,wikidata_id,confirmed_log_y_hat_percent_change)) %>% filter(wikidata_id=="Q148") %>% 
        mutate(group=paste(dataset, wikidata_id,confirmed_log_group_number)) %>%
        arrange(date_asdate) #%>%
        #mutate( confirmed_log_y_hat_percent_change = breakpoints(formula=confirmed_log_y_hat_percent_change ~ 1, data=. ) %>% fitted.values() )

p_interpolation0 <- test %>%
                    ggplot() + 
                       geom_point( aes(x=date_asdate, y=confirmed_log, color=dataset), alpha=.3) +
                       geom_line( aes(x=date_asdate, y=confirmed_log_y_hat, color=dataset, group=group)) + #
                       #geom_line(data=temp_df2, aes(x=date_asdate, y=y_hat_mean), color="black", linetype = "dashed") +
                       theme_bw() +
                       ggtitle("China Q148 Confirmed") + facet_wrap(~dataset   )

Data on China shows variation across datasets for when they start measuring. Only two observe the very beginning of the outbreak. All of the datasets show a discontinuity where reporting standards must have changed. Our method attempts to bridge that gap in 3 of the series but not two others.

p_interpolation0

Italy

#Italy
#"Q38"

test <- lhs_long_clean_imputed %>% mutate(group=paste(dataset,wikidata_id,confirmed_log_y_hat_percent_change)) %>% filter(wikidata_id=="Q38") %>% 
        mutate(group=paste(dataset, wikidata_id,confirmed_log_group_number)) %>%
        arrange(date_asdate) #%>%
        #mutate( confirmed_log_y_hat_percent_change = breakpoints(formula=confirmed_log_y_hat_percent_change ~ 1, data=. ) %>% fitted.values() )

p_interpolation1 <- test %>%
                    ggplot() + 
                       geom_point( aes(x=date_asdate, y=confirmed_log, color=dataset), alpha=.3) +
                       geom_line( aes(x=date_asdate, y=confirmed_log_y_hat, color=dataset, group=group)) + #
                       #geom_line(data=temp_df2, aes(x=date_asdate, y=y_hat_mean), color="black", linetype = "dashed") +
                       theme_bw() +
                       ggtitle("Italy Q38 Confirmed") + facet_wrap(~dataset   )

Italy likewise shows variation in the start of recording across datasets. There’s also variation in the initial sparcity. Wikipedia is strangely missing data in the middle. Our method linearly interpolates into that space in a way in a way we probably don’t want.

p_interpolation1

Italy

#US
#"Q30"

test <- lhs_long_clean_imputed %>% mutate(group=paste(dataset,wikidata_id,confirmed_log_y_hat_percent_change)) %>% filter(wikidata_id=="Q30") %>% 
        mutate(group=paste(dataset, wikidata_id,confirmed_log_group_number)) %>%
        arrange(date_asdate) #%>%
        #mutate( confirmed_log_y_hat_percent_change = breakpoints(formula=confirmed_log_y_hat_percent_change ~ 1, data=. ) %>% fitted.values() )

p_interpolation2 <- test %>%
                    ggplot() + 
                       geom_point( aes(x=date_asdate, y=confirmed_log, color=dataset), alpha=.3) +
                       geom_line( aes(x=date_asdate, y=confirmed_log_y_hat, color=dataset, group=group)) + #
                       #geom_line(data=temp_df2, aes(x=date_asdate, y=y_hat_mean), color="black", linetype = "dashed") +
                       theme_bw() +
                       ggtitle("US Q30 Confirmed") + facet_wrap(~dataset   )
p_interpolation2

New York State

#US
#"Q30"

test <- lhs_long_clean_imputed %>% mutate(group=paste(dataset,wikidata_id,confirmed_log_y_hat_percent_change)) %>% filter(wikidata_id=="Q1384") %>% 
        mutate(group=paste(dataset, wikidata_id,confirmed_log_group_number)) %>%
        arrange(date_asdate) #%>%
        #mutate( confirmed_log_y_hat_percent_change = breakpoints(formula=confirmed_log_y_hat_percent_change ~ 1, data=. ) %>% fitted.values() )

p_interpolation3 <- test %>%
                    ggplot() + 
                       geom_point( aes(x=date_asdate, y=confirmed_log, color=dataset), alpha=.3) +
                       geom_line( aes(x=date_asdate, y=confirmed_log_y_hat, color=dataset, group=group)) + #
                       #geom_line(data=temp_df2, aes(x=date_asdate, y=y_hat_mean), color="black", linetype = "dashed") +
                       theme_bw() +
                       ggtitle("New York State Q1384 Confirmed") + facet_wrap(~dataset   )
p_interpolation3

New York City (by county)

nyt has it just by city, it doesn’t break it down by the boroughs. But because gadm doesn’t do cities we don’t assign it a qcode.

usafacts has it as New York County which is New York County (Manhattan)

#Brooklyn (Q18419)
test <- lhs_long_clean_imputed %>% mutate(group=paste(dataset,wikidata_id,confirmed_log_y_hat_percent_change)) %>% filter(wikidata_id=="Q855974") %>%  #no hits?
        mutate(group=paste(dataset, wikidata_id,confirmed_log_group_number)) %>%
        arrange(date_asdate) #%>%
        #mutate( confirmed_log_y_hat_percent_change = breakpoints(formula=confirmed_log_y_hat_percent_change ~ 1, data=. ) %>% fitted.values() )

p_interpolation4a <- test %>%
                    ggplot() + 
                       geom_point( aes(x=date_asdate, y=confirmed_log, color=dataset), alpha=.3) +
                       geom_line( aes(x=date_asdate, y=confirmed_log_y_hat, color=dataset, group=group)) + #
                       #geom_line(data=temp_df2, aes(x=date_asdate, y=y_hat_mean), color="black", linetype = "dashed") +
                       theme_bw() +
                       ggtitle("Bronx County (Q855974)") + facet_wrap(~dataset   ) + guides( color = FALSE)

#Queens County, New York Q5142559
test <- lhs_long_clean_imputed %>% mutate(group=paste(dataset,wikidata_id,confirmed_log_y_hat_percent_change)) %>% filter(wikidata_id=="Q5142559") %>%  #no hits?
        mutate(group=paste(dataset, wikidata_id,confirmed_log_group_number)) %>%
        arrange(date_asdate) #%>%
        #mutate( confirmed_log_y_hat_percent_change = breakpoints(formula=confirmed_log_y_hat_percent_change ~ 1, data=. ) %>% fitted.values() )

p_interpolation4b <- test %>%
                    ggplot() + 
                       geom_point( aes(x=date_asdate, y=confirmed_log, color=dataset), alpha=.3) +
                       geom_line( aes(x=date_asdate, y=confirmed_log_y_hat, color=dataset, group=group)) + #
                       #geom_line(data=temp_df2, aes(x=date_asdate, y=y_hat_mean), color="black", linetype = "dashed") +
                       theme_bw() +
                       ggtitle("Queens County, New York Q5142559") + facet_wrap(~dataset   ) + guides( color = FALSE)

#Brooklyn is aparently Kings County Q11980692
test <- lhs_long_clean_imputed %>% mutate(group=paste(dataset,wikidata_id,confirmed_log_y_hat_percent_change)) %>% filter(wikidata_id=="Q11980692") %>%  #no hits?
        mutate(group=paste(dataset, wikidata_id,confirmed_log_group_number)) %>%
        arrange(date_asdate) #%>%
        #mutate( confirmed_log_y_hat_percent_change = breakpoints(formula=confirmed_log_y_hat_percent_change ~ 1, data=. ) %>% fitted.values() )

p_interpolation4c <- test %>%
                    ggplot() + 
                       geom_point( aes(x=date_asdate, y=confirmed_log, color=dataset), alpha=.3) +
                       geom_line( aes(x=date_asdate, y=confirmed_log_y_hat, color=dataset, group=group)) + #
                       #geom_line(data=temp_df2, aes(x=date_asdate, y=y_hat_mean), color="black", linetype = "dashed") +
                       theme_bw() +
                       ggtitle("Brooklyn is Kings County Q11980692") + facet_wrap(~dataset   ) + guides( color = FALSE)

# Manhattan is New York County Q500416
test <- lhs_long_clean_imputed %>% mutate(group=paste(dataset,wikidata_id,confirmed_log_y_hat_percent_change)) %>% filter(wikidata_id=="Q500416") %>%  #no hits?
        mutate(group=paste(dataset, wikidata_id,confirmed_log_group_number)) %>%
        arrange(date_asdate) #%>%
        #mutate( confirmed_log_y_hat_percent_change = breakpoints(formula=confirmed_log_y_hat_percent_change ~ 1, data=. ) %>% fitted.values() )

p_interpolation4d <- test %>%
                    ggplot() + 
                       geom_point( aes(x=date_asdate, y=confirmed_log, color=dataset), alpha=.3) +
                       geom_line( aes(x=date_asdate, y=confirmed_log_y_hat, color=dataset, group=group)) + #
                       #geom_line(data=temp_df2, aes(x=date_asdate, y=y_hat_mean), color="black", linetype = "dashed") +
                       theme_bw() +
                       ggtitle("Manhattan is New York County Q500416") + facet_wrap(~dataset   ) + guides( color = FALSE)

#Staten Island is richmond county Q11997784
test <- lhs_long_clean_imputed %>% mutate(group=paste(dataset,wikidata_id,confirmed_log_y_hat_percent_change)) %>% filter(wikidata_id=="Q11997784") %>%  #no hits?
        mutate(group=paste(dataset, wikidata_id,confirmed_log_group_number)) %>%
        arrange(date_asdate) #%>%
        #mutate( confirmed_log_y_hat_percent_change = breakpoints(formula=confirmed_log_y_hat_percent_change ~ 1, data=. ) %>% fitted.values() )

p_interpolation4e <- test %>%
                    ggplot() + 
                       geom_point( aes(x=date_asdate, y=confirmed_log, color=dataset), alpha=.3) +
                       geom_line( aes(x=date_asdate, y=confirmed_log_y_hat, color=dataset, group=group)) + #
                       #geom_line(data=temp_df2, aes(x=date_asdate, y=y_hat_mean), color="black", linetype = "dashed") +
                       theme_bw() +
                       ggtitle("Staten Island  Richmond County Q11997784") + facet_wrap(~dataset   ) + guides( color = FALSE)

Note that CSSE is conflating all of New York City with Manhattan/New York County, Bing is too I think

p_interpolation4a + p_interpolation4b + p_interpolation4c + p_interpolation4d + p_interpolation4e

Plots by Countries

library(data.table)
geonames <- fread("/media/skynet2/905884f0-7546-4273-9061-12a790830beb/rwd_github_private/NESScovid19/data_temp/allCountries.txt", sep="\t") %>% mutate_if(is.numeric,as.character) %>% mutate_if(is.factor,as.character)
|--------------------------------------------------|
|==================================================|
|--------------------------------------------------|
|==================================================|
Found and resolved improper quoting out-of-sample. First healed line 522433: <<8436127  "Baki-Pilsen" Brewery   "Baki-Pilsen" Brewery       40.32864    49.78044    P   PPLL    AZ                      0       -25 Asia/Baku   2012-12-17>>. If the fields are not quoted (e.g. field separator does not appear within any field), try quote="" to avoid this warning.
dim(geonames) #12,006,426
[1] 12006426       19
geonames_small <- geonames %>% dplyr::select(geonameid=V1, name_text=V2) %>% inner_join( lhs_long_clean_imputed %>% dplyr::select(geonameid) %>% distinct() )
Joining, by = "geonameid"
dim(geonames_small)
[1] 4108    2

Confirmed

p_confirmed_by_country <- lhs_long_clean_imputed %>%
                          filter(!gid %>% str_detect("_") ) %>%
                          left_join(geonames_small  ) %>% mutate(name_text %>% as.factor()) %>%
                          mutate(group=paste(gid_geonameid_wikidata_id,confirmed_log_group_number)) %>%
                          ggplot() + 
                             #geom_point( aes(x=date_asdate, y=confirmed_log, color=dataset), alpha=.3) +
                             geom_line( aes(x=date_asdate, y=confirmed_log_y_hat, color=dataset, group=group)) + #
                             #geom_line(data=temp_df2, aes(x=date_asdate, y=y_hat_mean), color="black", linetype = "dashed") +
                             theme_bw() +
                             ggtitle("Confirmed (log) by Country") + facet_wrap(~name_text   ) + guides( color = FALSE) +
                            theme(
                              strip.background = element_blank()
                            ,  strip.text.x = element_blank()
                            )
p_confirmed_by_country

Deaths

p_deaths_by_country <- lhs_long_clean_imputed %>%
                          filter(!gid %>% str_detect("_") ) %>%
                          left_join(geonames_small  ) %>% mutate(name_text %>% as.factor()) %>%
                          mutate(group=paste(gid_geonameid_wikidata_id,confirmed_log_group_number)) %>%
                          ggplot() + 
                             #geom_point( aes(x=date_asdate, y=deaths_log_y_hat, color=dataset), alpha=.3) +
                             geom_line( aes(x=date_asdate, y=deaths_log_y_hat, color=dataset, group=group)) + #
                             #geom_line(data=temp_df2, aes(x=date_asdate, y=y_hat_mean), color="black", linetype = "dashed") +
                             theme_bw() +
                             ggtitle("Deaths (log) by Country") + facet_wrap(~name_text   ) + guides( color = FALSE) +
                            theme(
                              strip.background = element_blank()
                            ,  strip.text.x = element_blank()
                            )
p_deaths_by_country

Tests

p_tested_people_by_country <- lhs_long_clean_imputed %>%
                          filter(!gid %>% str_detect("_") ) %>%
                          left_join(geonames_small  ) %>% mutate(name_text %>% as.factor()) %>%
                          mutate(group=paste(gid_geonameid_wikidata_id,confirmed_log_group_number)) %>%
                          ggplot() + 
                             #geom_point( aes(x=date_asdate, y=tested_people_log_y_hat, color=dataset), alpha=.3) +
                             geom_line( aes(x=date_asdate, y=tested_people_log_y_hat, color=dataset, group=group)) + #
                             #geom_line(data=temp_df2, aes(x=date_asdate, y=y_hat_mean), color="black", linetype = "dashed") +
                             theme_bw() +
                             ggtitle("Tests (log) by Country") + facet_wrap(~name_text   ) + guides( color = FALSE) +
                            theme(
                              strip.background = element_blank()
                            ,  strip.text.x = element_blank()
                            )
p_tested_people_by_country

Interpolation of Rate of Change

Plot Confirmed Curves for Select Locations


library(patchwork)
lhs_long_clean_imputed <- readRDS( "/media/skynet2/905884f0-7546-4273-9061-12a790830beb/rwd_github_private/NESScovid19/data_temp/lhs_long_clean_imputed.Rds")
dim(lhs_long_clean_imputed) #45,609 #337043
#we want the colors to be consistent by dataset too btw

#####
#USA Q30

#bp_temp <- breakpoints(formula=confirmed_log_y_hat_percent_change ~ 1, data=temp_df %>% mutate(group=paste(dataset,wikidata_id,confirmed_log_y_hat_percent_change)) %>% filter(wikidata_id=="Q30"))
#confirmed_log_y_hat_percent_change=fitted.values(bp_temp)

test <- lhs_long_clean_imputed %>%
        mutate(group=paste(dataset,wikidata_id,confirmed_log_group_number)) %>%
        filter(wikidata_id=="Q30") %>% 
        arrange(date_asdate)  %>%
        mutate(date_asnumeric = date_asdate %>% as.numeric() )

#rt1 <- rpart(formula = confirmed_log_y_hat_percent_change ~ date_asnumeric, data=test)
#interpolated = data.frame(date_asnumeric=min(test$date_asnumeric):max(test$date_asnumeric) )
#interpolated$confirmed_log_y_hat_percent_change_y_hat <-  predict(rt1, newdata=interpolated)
#interpolated$date_asdate <- as.Date(interpolated$date_asnumeric)

p0a <- test %>%
        ggplot() + 
           geom_point( aes(x=date_asdate, y=confirmed_log, color=dataset), alpha=.3) +
           geom_line( aes(x=date_asdate, y=confirmed_log_y_hat, color=dataset, group=group)) + #
           #geom_line(data=temp_df2, aes(x=date_asdate, y=y_hat_mean), color="black", linetype = "dashed") +
           theme_bw() +
           ggtitle("USA Q30 Confirmed") # + facet_wrap(~dataset) 

p0b <- test %>%
       ggplot() + 
         geom_point( aes(x=date_asdate , y=confirmed_log_y_hat_percent_change, color=dataset), alpha=.3 ) +
         geom_line(aes(x=date_asdate , y=confirmed_log_y_hat_percent_change_y_hat ), alpha=1, color="black"  ) +
         #geom_smooth( aes(x=date_asdate , y=confirmed_log_y_hat_percent_change), alpha=.3, span=.05) + #, span=.05
         #geom_line( aes(x=date_asdate, y=confirmed_log_y_hat, color=dataset, group=group)) + #
         #geom_line(data=temp_df2, aes(x=date_asdate, y=y_hat_mean), color="black", linetype = "dashed") +
         theme_bw() +
         ggtitle("USA Q30 Confirmed") # + facet_wrap(~dataset)+ ylab("Daily Percent Change Confirmed")

#p0a / p0b



#####
#China Q148

test <- lhs_long_clean_imputed %>% mutate(group=paste(dataset,wikidata_id,confirmed_log_group_number)) %>% filter(wikidata_id=="Q148") %>% 
        mutate(group=paste(dataset, wikidata_id,confirmed_log_group_number)) %>%
        arrange(date_asdate) #%>%

p1a <- test %>% 
ggplot() + 
   geom_point( aes(x=date_asdate, y=confirmed_log, color=dataset), alpha=.3) +
   geom_line( aes(x=date_asdate, y=confirmed_log_y_hat, color=dataset, group=group)) + #
   #geom_line(data=temp_df2, aes(x=date_asdate, y=y_hat_mean), color="black", linetype = "dashed") +
   theme_bw() +
   ggtitle("China Q148 Confirmed")

p1b <- test %>%
       ggplot() + 
         geom_point( aes(x=date_asdate , y=confirmed_log_y_hat_percent_change, color=dataset), alpha=.3) +
         geom_line(aes(x=date_asdate , y=confirmed_log_y_hat_percent_change_y_hat ), alpha=1, color="black") +
         #geom_smooth( aes(x=date_asdate , y=confirmed_log_y_hat_percent_change), alpha=.3, span=.05) + #, span=.05
         #geom_line( aes(x=date_asdate, y=confirmed_log_y_hat, color=dataset, group=group)) + #
         #geom_line(data=temp_df2, aes(x=date_asdate, y=y_hat_mean), color="black", linetype = "dashed") +
         theme_bw() +
   ggtitle("China Q148 Confirmed")+ ylab("Daily Percent Change Confirmed")
   

#p1a / p1b

#India
#"Q668"

test <- lhs_long_clean_imputed %>% mutate(group=paste(dataset,wikidata_id,confirmed_log_y_hat_percent_change)) %>% filter(wikidata_id=="Q668") %>% 
        mutate(group=paste(dataset, wikidata_id,confirmed_log_group_number)) %>%
        arrange(date_asdate) #%>%
        #mutate( confirmed_log_y_hat_percent_change = breakpoints(formula=confirmed_log_y_hat_percent_change ~ 1, data=. ) %>% fitted.values() )


p2a <- test %>%
ggplot() + 
   geom_point( aes(x=date_asdate, y=confirmed_log, color=dataset), alpha=.3) +
   geom_line( aes(x=date_asdate, y=confirmed_log_y_hat, color=dataset, group=group)) + #
   #geom_line(data=temp_df2, aes(x=date_asdate, y=y_hat_mean), color="black", linetype = "dashed") +
   theme_bw() +
   ggtitle("India Q668 Confirmed")

p2b <- test %>%
       ggplot() + 
         geom_point( aes(x=date_asdate , y=confirmed_log_y_hat_percent_change, color=dataset), alpha=.3) +
         geom_line(aes(x=date_asdate , y=confirmed_log_y_hat_percent_change_y_hat ), alpha=1, color="black") +
         #geom_smooth( aes(x=date_asdate , y=confirmed_log_y_hat_percent_change), alpha=.3, span=.05) + #, span=.05
         #geom_line( aes(x=date_asdate, y=confirmed_log_y_hat, color=dataset, group=group)) + #
         #geom_line(data=temp_df2, aes(x=date_asdate, y=y_hat_mean), color="black", linetype = "dashed") +
         theme_bw() +
   ggtitle("India Q668 Confirmed")+ ylab("Daily Percent Change Confirmed")
 
  
#p2a / p2b



#Italy
#"Q38"

test <- lhs_long_clean_imputed %>% mutate(group=paste(dataset,wikidata_id,confirmed_log_y_hat_percent_change)) %>% filter(wikidata_id=="Q38") %>% 
        mutate(group=paste(dataset, wikidata_id,confirmed_log_group_number)) %>%
        arrange(date_asdate) #%>%
        #mutate( confirmed_log_y_hat_percent_change = breakpoints(formula=confirmed_log_y_hat_percent_change ~ 1, data=. ) %>% fitted.values() )


p4a <- test %>%
ggplot() + 
   geom_point( aes(x=date_asdate, y=confirmed_log, color=dataset), alpha=.3) +
   geom_line( aes(x=date_asdate, y=confirmed_log_y_hat, color=dataset, group=group)) + #
   #geom_line(data=temp_df2, aes(x=date_asdate, y=y_hat_mean), color="black", linetype = "dashed") +
   theme_bw() +
   ggtitle("Italy Q38 Confirmed")

p4b <- test %>%
       ggplot() + 
         geom_point( aes(x=date_asdate , y=confirmed_log_y_hat_percent_change, color=dataset), alpha=.3) +
         geom_line(aes(x=date_asdate , y=confirmed_log_y_hat_percent_change_y_hat ), alpha=1, color="black") +
         #geom_smooth( aes(x=date_asdate , y=confirmed_log_y_hat_percent_change), alpha=.3, span=.05) + #, span=.05
         #geom_line( aes(x=date_asdate, y=confirmed_log_y_hat, color=dataset, group=group)) + #
         #geom_line(data=temp_df2, aes(x=date_asdate, y=y_hat_mean), color="black", linetype = "dashed") +
         theme_bw() +
   ggtitle("Italy Q38 Confirmed")+ ylab("Daily Percent Change Confirmed")
   
    
#p4a / p4b



#South Korea
#"Q884"

test <- lhs_long_clean_imputed %>% mutate(group=paste(dataset,wikidata_id,confirmed_log_y_hat_percent_change)) %>% filter(wikidata_id=="Q884") %>% 
        mutate(group=paste(dataset, wikidata_id,confirmed_log_group_number)) %>%
        arrange(date_asdate) #%>%
        #mutate( confirmed_log_y_hat_percent_change = breakpoints(formula=confirmed_log_y_hat_percent_change ~ 1, data=. ) %>% fitted.values() )


p5a <- test %>%
ggplot() + 
   geom_point( aes(x=date_asdate, y=confirmed_log, color=dataset), alpha=.3) +
   geom_line( aes(x=date_asdate, y=confirmed_log_y_hat, color=dataset, group=group)) + #
   #geom_line(data=temp_df2, aes(x=date_asdate, y=y_hat_mean), color="black", linetype = "dashed") +
   theme_bw() +
   ggtitle("South Korea Q884  Confirmed")

p5b <- test %>%
       ggplot() + 
         geom_point( aes(x=date_asdate , y=confirmed_log_y_hat_percent_change, color=dataset), alpha=.3) +
         geom_line(aes(x=date_asdate , y=confirmed_log_y_hat_percent_change_y_hat ), alpha=1, color="black") +
         #geom_smooth( aes(x=date_asdate , y=confirmed_log_y_hat_percent_change), alpha=.3, span=.05) + #, span=.05
         #geom_line( aes(x=date_asdate, y=confirmed_log_y_hat, color=dataset, group=group)) + #
         #geom_line(data=temp_df2, aes(x=date_asdate, y=y_hat_mean), color="black", linetype = "dashed") +
         theme_bw() +
   ggtitle("South Korea Q884 Confirmed") + ylab("Daily Percent Change Confirmed")
   
    
#p5a / p5b
(p0a + p1a + p2a ) / (p0b + p1b + p2b )

( p4a + p5a) / ( p4b + p5b)



test <- lhs_long_clean_imputed %>% mutate(group=paste(dataset,wikidata_id,confirmed_log_y_hat_percent_change)) %>% filter(wikidata_id=="Q1439") %>% 
        mutate(group=paste(dataset, wikidata_id,confirmed_log_group_number)) %>%
        arrange(date_asdate) #%>%
        #mutate( confirmed_log_y_hat_percent_change = breakpoints(formula=confirmed_log_y_hat_percent_change ~ 1, data=. ) %>% fitted.values() )


p0a <- test %>%
      ggplot() + 
         geom_point( aes(x=date_asdate, y=confirmed_log, color=dataset), alpha=.3) +
         geom_line( aes(x=date_asdate, y=confirmed_log_y_hat, color=dataset, group=group)) + #
         #geom_line(data=temp_df2, aes(x=date_asdate, y=y_hat_mean), color="black", linetype = "dashed") +
         theme_bw() +
         ggtitle("Texas Q1439 Confirmed")

p0b <- test %>%
       ggplot() + 
         geom_point( aes(x=date_asdate , y=confirmed_log_y_hat_percent_change, color=dataset), alpha=.3) +
         geom_line(aes(x=date_asdate , y=confirmed_log_y_hat_percent_change_y_hat ), alpha=1, color="black") +
         #geom_smooth( aes(x=date_asdate , y=confirmed_log_y_hat_percent_change), alpha=.3, span=.05) + #, span=.05
         #geom_line( aes(x=date_asdate, y=confirmed_log_y_hat, color=dataset, group=group)) + #
         #geom_line(data=temp_df2, aes(x=date_asdate, y=y_hat_mean), color="black", linetype = "dashed") +
         theme_bw() +
         ggtitle("Texas Q1439 Confirmed") + ylim(0,100)+ ylab("Daily Percent Change Confirmed")

#Bexar
#"Q16861"
test <- lhs_long_clean_imputed %>% mutate(group=paste(dataset,wikidata_id,confirmed_log_y_hat_percent_change)) %>% filter(wikidata_id=="Q16861") %>% 
        mutate(group=paste(dataset, wikidata_id,confirmed_log_group_number)) %>%
        arrange(date_asdate) #%>%
        #mutate( confirmed_log_y_hat_percent_change = breakpoints(formula=confirmed_log_y_hat_percent_change ~ 1, data=. ) %>% fitted.values() )
p1a <- test %>%
      ggplot() + 
         geom_point( aes(x=date_asdate, y=confirmed_log, color=dataset), alpha=.3) +
         geom_line( aes(x=date_asdate, y=confirmed_log_y_hat, color=dataset, group=group)) + #
         #geom_line(data=temp_df2, aes(x=date_asdate, y=y_hat_mean), color="black", linetype = "dashed") +
         theme_bw() +
         ggtitle("Bexar County Q16861 Confirmed")
p1b <- test %>%
       ggplot() + 
         geom_point( aes(x=date_asdate , y=confirmed_log_y_hat_percent_change, color=dataset), alpha=.3) +
         geom_line(aes(x=date_asdate , y=confirmed_log_y_hat_percent_change_y_hat ), alpha=1, color="black") +
         #geom_smooth( aes(x=date_asdate , y=confirmed_log_y_hat_percent_change), alpha=.3, span=.05) + #, span=.05
         #geom_line( aes(x=date_asdate, y=confirmed_log_y_hat, color=dataset, group=group)) + #
         #geom_line(data=temp_df2, aes(x=date_asdate, y=y_hat_mean), color="black", linetype = "dashed") +
         theme_bw() +
   ggtitle("Bexar County Q16861 Confirmed") + ylim(0,100)+ ylab("Daily Percent Change Confirmed")

#California
test <- lhs_long_clean_imputed %>% mutate(group=paste(dataset,wikidata_id,confirmed_log_y_hat_percent_change)) %>% filter(wikidata_id=="Q99") %>% 
        mutate(group=paste(dataset, wikidata_id,confirmed_log_group_number)) %>%
        arrange(date_asdate) #%>%
        #mutate( confirmed_log_y_hat_percent_change = breakpoints(formula=confirmed_log_y_hat_percent_change ~ 1, data=. ) %>% fitted.values() )
p2a <- test %>%
      ggplot() + 
         geom_point( aes(x=date_asdate, y=confirmed_log, color=dataset), alpha=.3) +
         geom_line( aes(x=date_asdate, y=confirmed_log_y_hat, color=dataset, group=group)) + #
         #geom_line(data=temp_df2, aes(x=date_asdate, y=y_hat_mean), color="black", linetype = "dashed") +
         theme_bw() +
         ggtitle("California Q99 Confirmed")
p2b <- test %>%
       ggplot() + 
         geom_point( aes(x=date_asdate , y=confirmed_log_y_hat_percent_change, color=dataset), alpha=.3) +
         geom_line(aes(x=date_asdate , y=confirmed_log_y_hat_percent_change_y_hat ), alpha=1, color="black") +
         #geom_smooth( aes(x=date_asdate , y=confirmed_log_y_hat_percent_change), alpha=.3, span=.05) + #, span=.05
         #geom_line( aes(x=date_asdate, y=confirmed_log_y_hat, color=dataset, group=group)) + #
         #geom_line(data=temp_df2, aes(x=date_asdate, y=y_hat_mean), color="black", linetype = "dashed") +
         theme_bw() +
         ggtitle("California Q99 Confirmed") + ylim(0,100)+ ylab("Daily Percent Change Confirmed")

#San Diego County (Q108143)
test <- lhs_long_clean_imputed %>% mutate(group=paste(dataset,wikidata_id,confirmed_log_y_hat_percent_change)) %>% filter(wikidata_id=="Q108143") %>% 
        mutate(group=paste(dataset, wikidata_id,confirmed_log_group_number)) %>%
        arrange(date_asdate) #%>%
        #mutate( confirmed_log_y_hat_percent_change = breakpoints(formula=confirmed_log_y_hat_percent_change ~ 1, data=. ) %>% fitted.values() )
p3a <- test %>%
      ggplot() + 
         geom_point( aes(x=date_asdate, y=confirmed_log, color=dataset), alpha=.3) +
         geom_line( aes(x=date_asdate, y=confirmed_log_y_hat, color=dataset, group=group)) + #
         #geom_line(data=temp_df2, aes(x=date_asdate, y=y_hat_mean), color="black", linetype = "dashed") +
         theme_bw() +
         ggtitle("San Diego County (Q108143) Confirmed")
p3b <- test %>%
       ggplot() + 
         geom_point( aes(x=date_asdate , y=confirmed_log_y_hat_percent_change, color=dataset), alpha=.3) +
         geom_line(aes(x=date_asdate , y=confirmed_log_y_hat_percent_change_y_hat ), alpha=1, color="black") +
         #geom_smooth( aes(x=date_asdate , y=confirmed_log_y_hat_percent_change), alpha=.3, span=.05) + #, span=.05
         #geom_line( aes(x=date_asdate, y=confirmed_log_y_hat, color=dataset, group=group)) + #
         #geom_line(data=temp_df2, aes(x=date_asdate, y=y_hat_mean), color="black", linetype = "dashed") +
         theme_bw() +
         ggtitle("San Diego County (Q108143) Confirmed") + ylim(0,100)+ ylab("Daily Percent Change Confirmed")

#Florida (Q812)
test <- lhs_long_clean_imputed %>% mutate(group=paste(dataset,wikidata_id,confirmed_log_y_hat_percent_change)) %>% filter(wikidata_id=="Q812") %>% 
        mutate(group=paste(dataset, wikidata_id,confirmed_log_group_number)) %>%
        arrange(date_asdate) #%>%
        #mutate( confirmed_log_y_hat_percent_change = breakpoints(formula=confirmed_log_y_hat_percent_change ~ 1, data=. ) %>% fitted.values() )
p4a <- test %>%
      ggplot() + 
         geom_point( aes(x=date_asdate, y=confirmed_log, color=dataset), alpha=.3) +
         geom_line( aes(x=date_asdate, y=confirmed_log_y_hat, color=dataset, group=group)) + #
         #geom_line(data=temp_df2, aes(x=date_asdate, y=y_hat_mean), color="black", linetype = "dashed") +
         theme_bw() +
         ggtitle("Florida (Q812) Confirmed")
p4b <- test %>%
       ggplot() + 
         geom_point( aes(x=date_asdate , y=confirmed_log_y_hat_percent_change, color=dataset), alpha=.3) +
         geom_line(aes(x=date_asdate , y=confirmed_log_y_hat_percent_change_y_hat ), alpha=1, color="black") +
         #geom_smooth( aes(x=date_asdate , y=confirmed_log_y_hat_percent_change), alpha=.3, span=.05) + #, span=.05
         #geom_line( aes(x=date_asdate, y=confirmed_log_y_hat, color=dataset, group=group)) + #
         #geom_line(data=temp_df2, aes(x=date_asdate, y=y_hat_mean), color="black", linetype = "dashed") +
         theme_bw() +
         ggtitle("Florida (Q812) Confirmed") + ylim(0,100)+ ylab("Daily Percent Change Confirmed")


#St. Lucie County (Q494564)
test <- lhs_long_clean_imputed %>% mutate(group=paste(dataset,wikidata_id,confirmed_log_y_hat_percent_change)) %>% filter(wikidata_id=="Q494564") %>% 
        mutate(group=paste(dataset, wikidata_id,confirmed_log_group_number)) %>%
        arrange(date_asdate) #%>%
        #mutate( confirmed_log_y_hat_percent_change = breakpoints(formula=confirmed_log_y_hat_percent_change ~ 1, data=. ) %>% fitted.values() )
p5a <- test %>%
      ggplot() + 
         geom_point( aes(x=date_asdate, y=confirmed_log, color=dataset), alpha=.3) +
         geom_line( aes(x=date_asdate, y=confirmed_log_y_hat, color=dataset, group=group)) + #
         #geom_line(data=temp_df2, aes(x=date_asdate, y=y_hat_mean), color="black", linetype = "dashed") +
         theme_bw() +
         ggtitle("St. Lucie County (Q494564) Confirmed")
p5b <- test %>%
       ggplot() + 
         geom_point( aes(x=date_asdate , y=confirmed_log_y_hat_percent_change, color=dataset), alpha=.3) +
         geom_line(aes(x=date_asdate , y=confirmed_log_y_hat_percent_change_y_hat ), alpha=1, color="black") +
         #geom_smooth( aes(x=date_asdate , y=confirmed_log_y_hat_percent_change), alpha=.3, span=.05) + #, span=.05
         #geom_line( aes(x=date_asdate, y=confirmed_log_y_hat, color=dataset, group=group)) + #
         #geom_line(data=temp_df2, aes(x=date_asdate, y=y_hat_mean), color="black", linetype = "dashed") +
         theme_bw() +
         ggtitle("St. Lucie County (Q494564) Confirmed") + ylim(0,100)+ ylab("Daily Percent Change Confirmed")
#Not counting slopes that were interpolated out of domain fixed california's plot
( p0a + p1a ) / ( p0b + p1b )

( p2a + p3a ) / ( p2b + p3b )

( p4a + p5a) / ( p4b + p5b)

Plot Death Curves for Select Locations

Show how interpolation works on deaths


test <- lhs_long_clean_imputed %>%
        mutate(group=paste(dataset,wikidata_id,deaths_log_group_number)) %>%
        filter(wikidata_id=="Q30") %>% 
        arrange(date_asdate)  %>%
        mutate(date_asnumeric = date_asdate %>% as.numeric() )

p0a <- test %>%
        ggplot() + 
           geom_point( aes(x=date_asdate, y=deaths_log, color=dataset), alpha=.3) +
           geom_line( aes(x=date_asdate, y=deaths_log_y_hat, color=dataset, group=group)) + #
           #geom_line(data=temp_df2, aes(x=date_asdate, y=y_hat_mean), color="black", linetype = "dashed") +
           theme_bw() +
           ggtitle("USA Q30 Deaths") # + facet_wrap(~dataset) 

p0b <- test %>%
       ggplot() + 
         geom_point( aes(x=date_asdate , y=deaths_log_y_hat_percent_change, color=dataset), alpha=.3 ) +
         geom_line(aes(x=date_asdate , y=deaths_log_y_hat_percent_change_y_hat ), alpha=1, color="black"  ) +
         #geom_smooth( aes(x=date_asdate , y=deaths_log_y_hat_percent_change), alpha=.3, span=.05) + #, span=.05
         #geom_line( aes(x=date_asdate, y=deaths_log_y_hat, color=dataset, group=group)) + #
         #geom_line(data=temp_df2, aes(x=date_asdate, y=y_hat_mean), color="black", linetype = "dashed") +
         theme_bw() +
         ggtitle("USA Q30 Deaths") + ylab("Daily Percent Change Deaths") # + facet_wrap(~dataset)

#p0a / p0b


#####
#China Q148

test <- lhs_long_clean_imputed %>% mutate(group=paste(dataset,wikidata_id,deaths_log_group_number)) %>% filter(wikidata_id=="Q148") %>% 
        mutate(group=paste(dataset, wikidata_id,deaths_log_group_number)) %>%
        arrange(date_asdate) #%>%

p1a <- test %>% 
ggplot() + 
   geom_point( aes(x=date_asdate, y=deaths_log, color=dataset), alpha=.3) +
   geom_line( aes(x=date_asdate, y=deaths_log_y_hat, color=dataset, group=group)) + #
   #geom_line(data=temp_df2, aes(x=date_asdate, y=y_hat_mean), color="black", linetype = "dashed") +
   theme_bw() +
   ggtitle("China Q148 Deaths")

p1b <- test %>%
       ggplot() + 
         geom_point( aes(x=date_asdate , y=deaths_log_y_hat_percent_change, color=dataset), alpha=.3) +
         geom_line(aes(x=date_asdate , y=deaths_log_y_hat_percent_change_y_hat ), alpha=1, color="black") +
         #geom_smooth( aes(x=date_asdate , y=deaths_log_y_hat_percent_change), alpha=.3, span=.05) + #, span=.05
         #geom_line( aes(x=date_asdate, y=deaths_log_y_hat, color=dataset, group=group)) + #
         #geom_line(data=temp_df2, aes(x=date_asdate, y=y_hat_mean), color="black", linetype = "dashed") +
         theme_bw() +
   ggtitle("China Q148 Deaths")+ ylab("Daily Percent Change Deaths")
   

#p1a / p1b

#India
#"Q668"

test <- lhs_long_clean_imputed %>% mutate(group=paste(dataset,wikidata_id,deaths_log_y_hat_percent_change)) %>% filter(wikidata_id=="Q668") %>% 
        mutate(group=paste(dataset, wikidata_id,deaths_log_group_number)) %>%
        arrange(date_asdate) #%>%
        #mutate( deaths_log_y_hat_percent_change = breakpoints(formula=deaths_log_y_hat_percent_change ~ 1, data=. ) %>% fitted.values() )


p2a <- test %>%
ggplot() + 
   geom_point( aes(x=date_asdate, y=deaths_log, color=dataset), alpha=.3) +
   geom_line( aes(x=date_asdate, y=deaths_log_y_hat, color=dataset, group=group)) + #
   #geom_line(data=temp_df2, aes(x=date_asdate, y=y_hat_mean), color="black", linetype = "dashed") +
   theme_bw() +
   ggtitle("India Q668 Deaths")

p2b <- test %>%
       ggplot() + 
         geom_point( aes(x=date_asdate , y=deaths_log_y_hat_percent_change, color=dataset), alpha=.3) +
         geom_line(aes(x=date_asdate , y=deaths_log_y_hat_percent_change_y_hat ), alpha=1, color="black") +
         #geom_smooth( aes(x=date_asdate , y=deaths_log_y_hat_percent_change), alpha=.3, span=.05) + #, span=.05
         #geom_line( aes(x=date_asdate, y=deaths_log_y_hat, color=dataset, group=group)) + #
         #geom_line(data=temp_df2, aes(x=date_asdate, y=y_hat_mean), color="black", linetype = "dashed") +
         theme_bw() +
   ggtitle("India Q668 Deaths")+ ylab("Daily Percent Change Deaths")
 
  
#p2a / p2b

#Bexar
#"Q16861"

test <- lhs_long_clean_imputed %>% mutate(group=paste(dataset,wikidata_id,deaths_log_y_hat_percent_change)) %>% filter(wikidata_id=="Q16861") %>% 
        mutate(group=paste(dataset, wikidata_id,deaths_log_group_number)) %>%
        arrange(date_asdate) #%>%
        #mutate( deaths_log_y_hat_percent_change = breakpoints(formula=deaths_log_y_hat_percent_change ~ 1, data=. ) %>% fitted.values() )


p3a <- test %>%
      ggplot() + 
         geom_point( aes(x=date_asdate, y=deaths_log, color=dataset), alpha=.3) +
         geom_line( aes(x=date_asdate, y=deaths_log_y_hat, color=dataset, group=group)) + #
         #geom_line(data=temp_df2, aes(x=date_asdate, y=y_hat_mean), color="black", linetype = "dashed") +
         theme_bw() +
         ggtitle("Bexar County Q16861 Deaths")

p3b <- test %>%
       ggplot() + 
         geom_point( aes(x=date_asdate , y=deaths_log_y_hat_percent_change, color=dataset), alpha=.3) +
         geom_line(aes(x=date_asdate , y=deaths_log_y_hat_percent_change_y_hat ), alpha=1, color="black") +
         #geom_smooth( aes(x=date_asdate , y=deaths_log_y_hat_percent_change), alpha=.3, span=.05) + #, span=.05
         #geom_line( aes(x=date_asdate, y=deaths_log_y_hat, color=dataset, group=group)) + #
         #geom_line(data=temp_df2, aes(x=date_asdate, y=y_hat_mean), color="black", linetype = "dashed") +
         theme_bw() +
   ggtitle("Bexar County Q16861 Deaths") + ylim(0,100)+ ylab("Daily Percent Change Deaths")
   
#p3a / p3b



#Italy
#"Q38"

test <- lhs_long_clean_imputed %>% mutate(group=paste(dataset,wikidata_id,deaths_log_y_hat_percent_change)) %>% filter(wikidata_id=="Q38") %>% 
        mutate(group=paste(dataset, wikidata_id,deaths_log_group_number)) %>%
        arrange(date_asdate) #%>%
        #mutate( deaths_log_y_hat_percent_change = breakpoints(formula=deaths_log_y_hat_percent_change ~ 1, data=. ) %>% fitted.values() )


p4a <- test %>%
ggplot() + 
   geom_point( aes(x=date_asdate, y=deaths_log, color=dataset), alpha=.3) +
   geom_line( aes(x=date_asdate, y=deaths_log_y_hat, color=dataset, group=group)) + #
   #geom_line(data=temp_df2, aes(x=date_asdate, y=y_hat_mean), color="black", linetype = "dashed") +
   theme_bw() +
   ggtitle("Italy Q38 Deaths")

p4b <- test %>%
       ggplot() + 
         geom_point( aes(x=date_asdate , y=deaths_log_y_hat_percent_change, color=dataset), alpha=.3) +
         geom_line(aes(x=date_asdate , y=deaths_log_y_hat_percent_change_y_hat ), alpha=1, color="black") +
         #geom_smooth( aes(x=date_asdate , y=deaths_log_y_hat_percent_change), alpha=.3, span=.05) + #, span=.05
         #geom_line( aes(x=date_asdate, y=deaths_log_y_hat, color=dataset, group=group)) + #
         #geom_line(data=temp_df2, aes(x=date_asdate, y=y_hat_mean), color="black", linetype = "dashed") +
         theme_bw() +
   ggtitle("Italy Q38 Deaths")+ ylab("Daily Percent Change Deaths")
   
    
#p4a / p4b



#South Korea
#"Q884"

test <- lhs_long_clean_imputed %>% mutate(group=paste(dataset,wikidata_id,deaths_log_y_hat_percent_change)) %>% filter(wikidata_id=="Q884") %>% 
        mutate(group=paste(dataset, wikidata_id,deaths_log_group_number)) %>%
        arrange(date_asdate) #%>%
        #mutate( deaths_log_y_hat_percent_change = breakpoints(formula=deaths_log_y_hat_percent_change ~ 1, data=. ) %>% fitted.values() )


p5a <- test %>%
ggplot() + 
   geom_point( aes(x=date_asdate, y=deaths_log, color=dataset), alpha=.3) +
   geom_line( aes(x=date_asdate, y=deaths_log_y_hat, color=dataset, group=group)) + #
   #geom_line(data=temp_df2, aes(x=date_asdate, y=y_hat_mean), color="black", linetype = "dashed") +
   theme_bw() +
   ggtitle("South Korea Q884  Deaths")

p5b <- test %>%
       ggplot() + 
         geom_point( aes(x=date_asdate , y=deaths_log_y_hat_percent_change, color=dataset), alpha=.3) +
         geom_line(aes(x=date_asdate , y=deaths_log_y_hat_percent_change_y_hat ), alpha=1, color="black") +
         #geom_smooth( aes(x=date_asdate , y=deaths_log_y_hat_percent_change), alpha=.3, span=.05) + #, span=.05
         #geom_line( aes(x=date_asdate, y=deaths_log_y_hat, color=dataset, group=group)) + #
         #geom_line(data=temp_df2, aes(x=date_asdate, y=y_hat_mean), color="black", linetype = "dashed") +
         theme_bw() +
   ggtitle("South Korea Q884 Deaths") + ylab("Daily Percent Change Deaths")
   
    
#p5a / p5b

I need to fix this, USA has a fraction of a death

Note the discontinuity in Chin when they added those 1k deaths to the total

India deaths is broken, we shouldn’t be interpolating a rate before we think the number is greater than 0

(p0a + p1a + p2a ) / (p0b + p1b + p2b )

(p3a + p4a + p5a) / (p3b + p4b + p5b)

Plot Testing Curves for Select Locations

Show how interpolation works on tested

US is an example where we interpolated past our available data. Shouldn’t do that either!


test <- lhs_long_clean_imputed %>%
        mutate(group=paste(dataset,wikidata_id,tested_people_log_group_number)) %>%
        filter(wikidata_id=="Q30") %>% 
        arrange(date_asdate)  %>%
        mutate(date_asnumeric = date_asdate %>% as.numeric() )

p0a <- test %>%
        ggplot() + 
           geom_point( aes(x=date_asdate, y=tested_people_log, color=dataset), alpha=.3) +
           geom_line( aes(x=date_asdate, y=tested_people_log_y_hat, color=dataset, group=group)) + #
           #geom_line(data=temp_df2, aes(x=date_asdate, y=y_hat_mean), color="black", linetype = "dashed") +
           theme_bw() +
           ggtitle("USA Q30 Tested")  #+ facet_wrap(~dataset) 

p0b <- test %>%
       ggplot() + 
         geom_point( aes(x=date_asdate , y=tested_people_log_y_hat_percent_change, color=dataset), alpha=.3 ) +
         geom_line(aes(x=date_asdate , y=tested_people_log_y_hat_percent_change_y_hat ), alpha=1, color="black"  ) +
         #geom_smooth( aes(x=date_asdate , y=tested_people_log_y_hat_percent_change), alpha=.3, span=.05) + #, span=.05
         #geom_line( aes(x=date_asdate, y=tested_people_log_y_hat, color=dataset, group=group)) + #
         #geom_line(data=temp_df2, aes(x=date_asdate, y=y_hat_mean), color="black", linetype = "dashed") +
         theme_bw() +
         ggtitle("USA Q30 tested_people") + ylab("Daily Percent Change tested_people") # + facet_wrap(~dataset)

#p0a / p0b


#####
#China Q148

test <- lhs_long_clean_imputed %>% mutate(group=paste(dataset,wikidata_id,tested_people_log_group_number)) %>% filter(wikidata_id=="Q148") %>% 
        mutate(group=paste(dataset, wikidata_id,tested_people_log_group_number)) %>%
        arrange(date_asdate) #%>%

p1a <- test %>% 
ggplot() + 
   geom_point( aes(x=date_asdate, y=tested_people_log, color=dataset), alpha=.3) +
   geom_line( aes(x=date_asdate, y=tested_people_log_y_hat, color=dataset, group=group)) + #
   #geom_line(data=temp_df2, aes(x=date_asdate, y=y_hat_mean), color="black", linetype = "dashed") +
   theme_bw() +
   ggtitle("China Q148 tested_people")

p1b <- test %>%
       ggplot() + 
         geom_point( aes(x=date_asdate , y=tested_people_log_y_hat_percent_change, color=dataset), alpha=.3) +
         geom_line(aes(x=date_asdate , y=tested_people_log_y_hat_percent_change_y_hat ), alpha=1, color="black") +
         #geom_smooth( aes(x=date_asdate , y=tested_people_log_y_hat_percent_change), alpha=.3, span=.05) + #, span=.05
         #geom_line( aes(x=date_asdate, y=tested_people_log_y_hat, color=dataset, group=group)) + #
         #geom_line(data=temp_df2, aes(x=date_asdate, y=y_hat_mean), color="black", linetype = "dashed") +
         theme_bw() +
   ggtitle("China Q148 tested_people")+ ylab("Daily Percent Change tested_people")
   

#p1a / p1b

#India
#"Q668"

test <- lhs_long_clean_imputed %>% mutate(group=paste(dataset,wikidata_id,tested_people_log_y_hat_percent_change)) %>% filter(wikidata_id=="Q668") %>% 
        mutate(group=paste(dataset, wikidata_id,tested_people_log_group_number)) %>%
        arrange(date_asdate) #%>%
        #mutate( tested_people_log_y_hat_percent_change = breakpoints(formula=tested_people_log_y_hat_percent_change ~ 1, data=. ) %>% fitted.values() )


p2a <- test %>%
ggplot() + 
   geom_point( aes(x=date_asdate, y=tested_people_log, color=dataset), alpha=.3) +
   geom_line( aes(x=date_asdate, y=tested_people_log_y_hat, color=dataset, group=group)) + #
   #geom_line(data=temp_df2, aes(x=date_asdate, y=y_hat_mean), color="black", linetype = "dashed") +
   theme_bw() +
   ggtitle("India Q668 tested_people")

p2b <- test %>%
       ggplot() + 
         geom_point( aes(x=date_asdate , y=tested_people_log_y_hat_percent_change, color=dataset), alpha=.3) +
         geom_line(aes(x=date_asdate , y=tested_people_log_y_hat_percent_change_y_hat ), alpha=1, color="black") +
         #geom_smooth( aes(x=date_asdate , y=tested_people_log_y_hat_percent_change), alpha=.3, span=.05) + #, span=.05
         #geom_line( aes(x=date_asdate, y=tested_people_log_y_hat, color=dataset, group=group)) + #
         #geom_line(data=temp_df2, aes(x=date_asdate, y=y_hat_mean), color="black", linetype = "dashed") +
         theme_bw() +
   ggtitle("India Q668 tested_people")+ ylab("Daily Percent Change tested_people")
 
  
#p2a / p2b

#Bexar
#"Q16861"

test <- lhs_long_clean_imputed %>% mutate(group=paste(dataset,wikidata_id,tested_people_log_y_hat_percent_change)) %>% filter(wikidata_id=="Q16861") %>% 
        mutate(group=paste(dataset, wikidata_id,tested_people_log_group_number)) %>%
        arrange(date_asdate) #%>%
        #mutate( tested_people_log_y_hat_percent_change = breakpoints(formula=tested_people_log_y_hat_percent_change ~ 1, data=. ) %>% fitted.values() )


p3a <- test %>%
      ggplot() + 
         geom_point( aes(x=date_asdate, y=tested_people_log, color=dataset), alpha=.3) +
         geom_line( aes(x=date_asdate, y=tested_people_log_y_hat, color=dataset, group=group)) + #
         #geom_line(data=temp_df2, aes(x=date_asdate, y=y_hat_mean), color="black", linetype = "dashed") +
         theme_bw() +
         ggtitle("Bexar County Q16861 tested_people")

p3b <- test %>%
       ggplot() + 
         geom_point( aes(x=date_asdate , y=tested_people_log_y_hat_percent_change, color=dataset), alpha=.3) +
         geom_line(aes(x=date_asdate , y=tested_people_log_y_hat_percent_change_y_hat ), alpha=1, color="black") +
         #geom_smooth( aes(x=date_asdate , y=tested_people_log_y_hat_percent_change), alpha=.3, span=.05) + #, span=.05
         #geom_line( aes(x=date_asdate, y=tested_people_log_y_hat, color=dataset, group=group)) + #
         #geom_line(data=temp_df2, aes(x=date_asdate, y=y_hat_mean), color="black", linetype = "dashed") +
         theme_bw() +
   ggtitle("Bexar County Q16861 tested_people") + ylim(0,100)+ ylab("Daily Percent Change tested_people")
   
#p3a / p3b



#Italy
#"Q38"

test <- lhs_long_clean_imputed %>% mutate(group=paste(dataset,wikidata_id,tested_people_log_y_hat_percent_change)) %>% filter(wikidata_id=="Q38") %>% 
        mutate(group=paste(dataset, wikidata_id,tested_people_log_group_number)) %>%
        arrange(date_asdate) #%>%
        #mutate( tested_people_log_y_hat_percent_change = breakpoints(formula=tested_people_log_y_hat_percent_change ~ 1, data=. ) %>% fitted.values() )


p4a <- test %>%
ggplot() + 
   geom_point( aes(x=date_asdate, y=tested_people_log, color=dataset), alpha=.3) +
   geom_line( aes(x=date_asdate, y=tested_people_log_y_hat, color=dataset, group=group)) + #
   #geom_line(data=temp_df2, aes(x=date_asdate, y=y_hat_mean), color="black", linetype = "dashed") +
   theme_bw() +
   ggtitle("Italy Q38 tested_people")

p4b <- test %>%
       ggplot() + 
         geom_point( aes(x=date_asdate , y=tested_people_log_y_hat_percent_change, color=dataset), alpha=.3) +
         geom_line(aes(x=date_asdate , y=tested_people_log_y_hat_percent_change_y_hat ), alpha=1, color="black") +
         #geom_smooth( aes(x=date_asdate , y=tested_people_log_y_hat_percent_change), alpha=.3, span=.05) + #, span=.05
         #geom_line( aes(x=date_asdate, y=tested_people_log_y_hat, color=dataset, group=group)) + #
         #geom_line(data=temp_df2, aes(x=date_asdate, y=y_hat_mean), color="black", linetype = "dashed") +
         theme_bw() +
   ggtitle("Italy Q38 tested_people")+ ylab("Daily Percent Change tested_people")
   
    
#p4a / p4b



#South Korea
#"Q884"

test <- lhs_long_clean_imputed %>% mutate(group=paste(dataset,wikidata_id,tested_people_log_y_hat_percent_change)) %>% filter(wikidata_id=="Q884") %>% 
        mutate(group=paste(dataset, wikidata_id,tested_people_log_group_number)) %>%
        arrange(date_asdate) #%>%
        #mutate( tested_people_log_y_hat_percent_change = breakpoints(formula=tested_people_log_y_hat_percent_change ~ 1, data=. ) %>% fitted.values() )


p5a <- test %>%
ggplot() + 
   geom_point( aes(x=date_asdate, y=tested_people_log, color=dataset), alpha=.3) +
   geom_line( aes(x=date_asdate, y=tested_people_log_y_hat, color=dataset, group=group)) + #
   #geom_line(data=temp_df2, aes(x=date_asdate, y=y_hat_mean), color="black", linetype = "dashed") +
   theme_bw() +
   ggtitle("South Korea Q884  tested_people")

p5b <- test %>%
       ggplot() + 
         geom_point( aes(x=date_asdate , y=tested_people_log_y_hat_percent_change, color=dataset), alpha=.3) +
         geom_line(aes(x=date_asdate , y=tested_people_log_y_hat_percent_change_y_hat ), alpha=1, color="black") +
         #geom_smooth( aes(x=date_asdate , y=tested_people_log_y_hat_percent_change), alpha=.3, span=.05) + #, span=.05
         #geom_line( aes(x=date_asdate, y=tested_people_log_y_hat, color=dataset, group=group)) + #
         #geom_line(data=temp_df2, aes(x=date_asdate, y=y_hat_mean), color="black", linetype = "dashed") +
         theme_bw() +
   ggtitle("South Korea Q884 tested_people") + ylab("Daily Percent Change tested_people")
   
    
#p5a / p5b

Note that China counts of testing are almost never given at the national level. We have some broken down by specific provinces but tables usually don’t have a “China” row.

(p0a + p1a + p2a ) / (p0b + p1b + p2b )

(p3a + p4a + p5a) / (p3b + p4b + p5b)

Aligning Curves by Takeoff

library(infotheo)
#Once we removed the no variance places my alignment has more mutual information than either first confirmed or 100 confirmed
mutinformation(X=df_slopes %>% dplyr::select(t,t_alligned,t_alligned_firstconfirmed,confirmed_log_y_hat_percent_change_y_hat) %>% discretize(), method="emp") #we outperformed t_alligned_100confirmed but it wasn't avail for most

#df_slopes %>% filter(abs(t_alligned)<20,abs(t_alligned_100confirmed_100)<20) %>% janitor::tabyl(t_alligned, t_alligned_100confirmed_100)
#hist(df_slopes$t_alligned - df_slopes$t_alligned_100confirmed_100, breaks=50)

Plot of curves raw and then curves alligned by takeoff start

The idea here is that completely unconstrained, COVID-19 growth should follow a logistic curve, flat, upswing, constant growth, downswing, and flat again. The assumption of no unconstrained growth no longer holds because the world is reacting, but there’s still a pretty uniformly characteristic upswing across geographic units. We look for this signal of the largest first difference in the daily percent change, call that the takeoff date, and then allign all the time series with that date as 0.

p_t_alligned_firstconfirmed  / p_t_alligned 

Plots by Countries

We have to add geocodes to the map placements



admin0 <- readRDS("/media/skynet2/905884f0-7546-4273-9061-12a790830beb/rwd_github_private/NESScovid19/data_in/admin0.Rds")
admin1 <- readRDS("/media/skynet2/905884f0-7546-4273-9061-12a790830beb/rwd_github_private/NESScovid19/data_in/admin1.Rds")
admin2 <- readRDS("/media/skynet2/905884f0-7546-4273-9061-12a790830beb/rwd_github_private/NESScovid19/data_in/admin2.Rds")

rex_clean <- function(x){ x %>% stringi::stri_trans_general("latin-ascii") %>% stringi::stri_replace_all(regex="[^A-Za-z0-9]","") %>% tolower() } #so individually, each string should be devoid of spaces,noncharacters, and nonlatin

rex_admin_function <- function(x) {
  x %>% 
  left_join(admin0 ) %>%
  left_join(admin1 )  %>%
  left_join(admin2 ) %>%
  mutate(gid=ifelse(!is.na(admin2_name_clean) & admin2_name_clean!='',gid2,ifelse(!is.na(admin1_name_clean) & admin1_name_clean!='', gid1, gid0))) %>%
  mutate(wikidata_id=ifelse(!is.na(admin2_name_clean) & admin2_name_clean!='',wikidata_id2,ifelse(!is.na(admin1_name_clean) & admin1_name_clean!='', wikidata_id1, wikidata_id0))) %>%
  mutate(geonameid=ifelse(!is.na(admin2_name_clean) & admin2_name_clean!='',geonameid2,ifelse(!is.na(admin1_name_clean) & admin1_name_clean!='', geonameid1, geonameid0))) %>%
  mutate(admin_level=ifelse(!is.na(admin2_name_clean) & admin2_name_clean!='',2,ifelse(!is.na(admin1_name_clean) & admin1_name_clean!='', 1, 0)))
}
install.packages("geofacet")
# or from github:
# devtools::install_github("hafen/geofacet")
library(geofacet)
head(us_state_grid2)
NA

Confirmed, Deaths, Tests

By country


gadm36 = st_read("/media/skynet2/905884f0-7546-4273-9061-12a790830beb/rwd_github_private/NESSgadm/data_in/gadm36_gpkg/gadm36.gpkg")
gadm36_df <- gadm36 %>% as.data.frame()
countries <- gadm36_df %>% dplyr::select(gid=GID_0, name=NAME_0 ) %>% distinct()

temp1 <- df_slopes %>%
          filter(!gid %>% str_detect("_") ) %>%
          left_join(countries %>% dplyr::select(gid, name_text=name) ) %>% 
          #left_join(geonames_small  ) %>% 
  
          mutate(name_text=name_text %>% as.factor()) %>%
          left_join(world_countries_grid1, by=c('gid'='code_alpha3')) %>%
          filter(!is.na(name))
temp2 <- temp1 %>% arrange(date_asdate) %>% filter(!duplicated(gid_geonameid_wikidata_id)) %>% mutate(name_text=name %>% as.factor())

head(world_countries_grid1)
world_countries_grid1_rex <- world_countries_grid1 %>% filter(name %in% temp2$name)
dim(world_countries_grid1_rex)
grid_preview(world_countries_grid1_rex)


p_confirmed_deaths_test_by_country <- temp1 %>% 
                                      ggplot() + 
                                         geom_line( aes(x=date_asdate, y=confirmed_log_y_hat), color="red") + # #t aligned is broken for the U.S. and some countries, all infinites
                                         geom_line( aes(x=date_asdate, y=deaths_log_y_hat), color="black") + #
                                         geom_line( aes(x=date_asdate, y=tested_people_log_y_hat), color="blue") + #
                                         theme_bw() +
                                         ggtitle("Global Covid-19: Log Tested (blue) Confirmed (red), Death (black)") +
                                        guides( color = FALSE) +
                                        facet_wrap(~name_text   ) +
                                        theme(
                                          strip.background = element_blank()
                                        ,  strip.text.x = element_blank()
                                        ) +
                                        geom_text(data=temp2,x=18282+20,y=14,aes(label=name_text), size=2.5) +
                                        ylab("Counts (log)") +
                                        xlab("Days before/Since Takeoff in Confirmed Numbers") +
                                        facet_geo(~name, grid =world_countries_grid1_rex) 
p_confirmed_deaths_test_by_country

U.S. by State


temp1 <- df_slopes %>%
          filter(gid %>% str_detect("USA\\.[0-9]{1,2}_1$") ) %>%
          left_join(geonames_small  ) %>% mutate(name_text= name_text %>% as.factor()) %>%
          left_join(us_state_grid2, by=c('name_text'='name')) %>% 
          filter(!is.na(name_text))
temp2 <- temp1 %>% arrange(date_asdate) %>% filter(!duplicated(gid_geonameid_wikidata_id)) %>% mutate(name_text=name_text %>% as.factor())

#t_alligned
p_confirmed_deaths_test_by_state_us <- temp1 %>% 
                                        #filter(gid=="USA") %>% #just a test
                                        ggplot() + 
                                           geom_line( aes(x=date_asdate, y=confirmed_log_y_hat), color="red") + # #t aligned is broken for the U.S. and some countries, all infinites
                                           geom_line( aes(x=date_asdate, y=deaths_log_y_hat), color="black") + #
                                           geom_line( aes(x=date_asdate, y=tested_people_log_y_hat), color="blue") + #
                                           theme_bw() +
                                           ggtitle("Covid-19 By U.S. State: Log Tested (blue) Confirmed (red), Death (black)") +
                                          theme(
                                            strip.background = element_blank()
                                          ,  strip.text.x = element_blank()
                                          ) +
                                          geom_text(data=temp2,x=18282+20,y=12,aes(label=name_text), size=4) +
                                          ylab("Counts (log)") + xlab("Date") + #"Days before/Since Takeoff in Confirmed Numbers"
                                          guides( color = FALSE) +
                                          facet_geo(~code) 

 
p_confirmed_deaths_test_by_state_us

India by State


head(india_grid2)

india_grid2_rex <- india_grid2 %>%
                    mutate(admin0_name_original="India") %>%
                    mutate(admin1_name_original=name) %>%
                    mutate(admin2_name_original='')  %>%
    
                    mutate(admin0_name_clean=admin0_name_original %>% rex_clean()) %>%
                    mutate(admin1_name_clean=admin1_name_original %>% rex_clean()) %>%
                    mutate(admin2_name_clean=admin2_name_original %>% rex_clean()) %>%
                    rex_admin_function()

temp1 <- df_slopes %>%
          filter(gid %>% str_detect("IND\\.[0-9]{1,2}_1$") ) %>%
          left_join(india_grid2_rex  ) %>% 
          mutate(name_text= admin1_name_original %>% as.factor()) %>% #set it to the state's name
          filter(!is.na(name_text))
temp2 <- temp1 %>% arrange(date_asdate) %>% filter(!duplicated(gid_geonameid_wikidata_id)) %>% mutate(name_text=name_text %>% as.factor())

#t_alligned
p_confirmed_deaths_test_by_state_india <- temp1 %>% 
                                          #filter(gid=="USA") %>% #just a test
                                          ggplot() + 
                                             geom_line( aes(x=date_asdate, y=confirmed_log_y_hat), color="red") + # #t aligned is broken for the U.S. and some countries, all infinites
                                             geom_line( aes(x=date_asdate, y=deaths_log_y_hat), color="black") + #
                                             geom_line( aes(x=date_asdate, y=tested_people_log_y_hat), color="blue") + #
                                             theme_bw() +
                                             ggtitle("Covid-19 By U.S. State: Log Tested (blue) Confirmed (red), Death (black)") +
                                            theme(
                                              strip.background = element_blank()
                                            ,  strip.text.x = element_blank()
                                            ) +
                                            geom_text(data=temp2,x=18282+50,y=7.5,aes(label=name_text), size=2.5) +
                                            ylab("Counts (log)") + xlab("Date") + #"Days before/Since Takeoff in Confirmed Numbers"
                                            guides( color = FALSE) +
                                            #Error: Other than 'row' and 'col', variable names of a custom grid must begin with 'code' or 'name'
                                            facet_geo(~code, grid = india_grid2 )  #_rex %>% filter(code, row, col, name)

 
p_confirmed_deaths_test_by_state_india

Tomorrow morning I think my job is to first difference all of these. How many tests, how many confirmed, how many dead each day. Find the lags and leads with the highest correlation between those three, possibly varying by country.

What this gives us is a nice normalized dataset where the task is to predict the shape of that distribution. We could try to predict time until the takeoff, the intensity of the growth at the takeoff point, the time until it returns to zero, the area under the curve, or every nook and change.

How does testing vary over this?

p_t_alligned_tested_people

Plot some specific countries


df_slopes %>% filter(!is.na(tested_people)) %>% count(wikidata_id) #292 places with testing information

df_slopes %>% filter(wikidata_id=="Q30") %>% ggplot() + geom_line(aes(x=date_asdate, y=confirmed)) + geom_line(aes(x=date_asdate, y=tested_people))


df_slopes %>% filter(wikidata_id=="Q30") %>% ggplot() + geom_line(aes(x=date_asdate, y=confirmed_log_y_hat)) + geom_line(aes(x=date_asdate, y=tested_people_log_y_hat))


df_slopes %>% filter(wikidata_id=="Q30") %>% ggplot() + geom_line(aes(x=date_asdate, y=confirmed/tested_people)) 



df_slopes %>% mutate(confirmed_over_tested_people=confirmed/tested_people) %>% pull(confirmed_over_tested_people) %>% summary()
    Min.  1st Qu.   Median     Mean  3rd Qu.     Max.     NA's 
    0.00     0.04     0.07     0.71     0.13 10556.60   142175 
df_slopes %>% mutate(confirmed_over_tested_people=confirmed/tested_people) %>% pull(confirmed_over_tested_people) %>% quantile(probs = seq(0, 1, 0.1), na.rm=T) #90th percential is ,23
          0%          10%          20%          30%          40%          50%          60%          70%          80%          90%         100% 
1.416411e-04 1.923077e-02 3.125000e-02 4.395604e-02 5.782918e-02 7.345162e-02 9.113021e-02 1.142857e-01 1.577514e-01 2.462857e-01 1.055660e+04 
df_slopes %>% ggplot() + geom_line(aes(x=t_alligned, y=confirmed/tested_people, color=wikidata_id), alpha=.2) + 
                             gghighlight(wikidata_id %in% c('Q30','Q1439','Q668','Q884','Q16861','Q159','Q38'), unhighlighted_params=list(alpha=.5)) +
                             geom_smooth( aes(x=t_alligned , y=confirmed/tested_people), span = 0.05) + 
                             xlim(-5,100) + ylim(0,.25) + theme_bw() #there are some outliars north of 10
Tried to calculate with group_by(), but the calculation failed.
Falling back to ungrouped filter operation...label_key: wikidata_id

options(gghighlight_max_labels = 60)
detach(gghighlight)
Error in detach(gghighlight) : invalid 'name' argument
lm1 <- lm(deaths ~  confirmed,data=lhs_long_median %>% filter(CFR<1))
lm2 <- lm(deaths ~ tested_people + confirmed,data=lhs_long_median %>% filter(CFR<1))

library(ggRandomForests); #install.packages('ggRandomForests')
rf1 <- rfsrc(deaths~ confirmed,
                      data=lhs_long_median %>% filter(CFR<1) %>% as.data.frame() )
gg_e <- gg_error(rf1)
gg_v <- gg_variable(rf1)
plot(gg_v, panel=TRUE, se=.95, span=1.2, alpha=.4) 

rf1 <- rfsrc(deaths~ confirmed + tested_people,
                      data=lhs_long_median %>% filter(CFR<1) %>% as.data.frame() )
gg_e <- gg_error(rf1)
gg_v <- gg_variable(rf1)
plot(gg_v, panel=TRUE, se=.95, span=1.2, alpha=.4)


rf2 <- rfsrc(CFR ~  tested_people_log,
                      data=lhs_long_median %>% 
                      mutate(CFR=deaths/confirmed) %>%
                      mutate(tested_people_log=log(tested_people+1)) %>%
                      filter(CFR<1) %>% as.data.frame()
             )
gg_v <- gg_variable(rf2)
plot(gg_v, panel=TRUE, se=.95, span=1.2, alpha=.4)

rf2 <- rfsrc(CFR ~  tested_people_log + confirmed_log,
                      data=lhs_long_median %>% 
                      mutate(CFR=deaths/confirmed) %>%
                      mutate(tested_people_log=log(tested_people+1)) %>%
                      mutate(confirmed_log=log(confirmed+1)) %>%
                      filter(CFR<1) %>% as.data.frame()
             )
gg_v <- gg_variable(rf2)
plot(gg_v, panel=TRUE, se=.95, span=1.2, alpha=.4)


#Throw in time
rf3 <- rfsrc(CFR ~  positive_perc + tested_people_log,
                                    data=lhs_long_median %>% 
                                    mutate(CFR=deaths/confirmed) %>%
                                    mutate(positive_perc=confirmed/tested_people) %>%
                                    mutate(tested_people_log=log(tested_people+1)) %>%
                                    mutate(confirmed_log=log(confirmed+1)) %>%
                                    filter(CFR<1) %>% as.data.frame()
             )
gg_v <- gg_variable(rf3)
plot(gg_v, panel=TRUE, se=.95, span=1.2, alpha=.4)

partial_Boston <- plot.variable(rf3,
partial=TRUE, sorted=FALSE,
show.plots = FALSE )

gg_p <- gg_partial(partial_Boston)
plot(gg_p, panel=TRUE, points = F )


copper_cts <-quantile_pts(lhs_long_median$tested_people_log, groups = 6, intervals = TRUE)
partial_coplot_Boston <- gg_partial_coplot(rf2, xvar="confirmed_log",
                                         groups=rm_grp,
                                         show.plots=FALSE)



summary(lhs_long_median$CFR)

lhs_long_median %>% filter(confirmed>10) %>% filter(CFR<1) %>% pull(CFR) %>% summary() #0.0297297  that's a median CFR of about 3%
lhs_long_median %>% filter(confirmed>10) %>% filter(CFR<1) %>% pull(CFR) %>% hist(breaks=50)

lhs_long_median %>% filter(confirmed>10) %>% filter(CFR<1) %>% ggplot(aes(x=CFR)) + geom_density()
#This code is now depricated in favor of the tree base method above

places <- lhs_long_clean$wikidata_id %>% unique() %>% na.omit() ; length(places)
datasets <- lhs_long_clean$dataset %>% unique() %>% na.omit() ; table(dataset)

temp_list <- list()
for(p in places){
    print(p)
    for(d in datasets){
      temp <- NULL
      temp <- lhs_long_clean %>% 
              arrange(date_asdate) %>% 
              filter(dataset %in% d) %>% 
              filter(wikidata_id %in% p) %>% 
              mutate(confirmed_log=log(confirmed+1)) %>%
              mutate(deaths_log=log(deaths+1)) %>%
              mutate(tested_people_log=log(tested_people+1)) %>%
              mutate(t= as.numeric(date_asdate) - min(as.numeric(date_asdate)) +1  ) %>% #start at 1 to make indexing easier
              mutate(i= row_number()  ) # actually need this
        
      i_original <- temp$i
      
      if( nrow(temp)==0 ) { next} #print("error");
      print(p)
      
      #bp <- breakpoints(confirmed_log ~ 1, data=temp)
      bp <- NULL
      lm1 <- NULL
      y_hat <- NA
      cdf <- NULL
      try({
            #if it fails fall back to just a lm
        lm1 <- lm(confirmed_log ~ 1 + t, data=temp)
    
        cdf <- data.frame(
                          t= 1, 
                          confirmed_log_intercept= coef(lm1)[1],
                          confirmed_log_slope= coef(lm1)[2],
                          confirmed_log_slope_break=0
                          )
        confirmed_log_y_hat=fitted.values(lm1)
      })
      
      try({
        bp <- breakpoints(confirmed_log ~ 1 + t, data=temp, h=3)
        
        cdf <- data.frame(
                          i= c(1,bp$breakpoints), 
                          confirmed_log_intercept= coef(bp)[,1],
                          confirmed_log_slope= coef(bp)[,2],
                          confirmed_log_slope_break=1
                          )
        confirmed_log_y_hat=fitted.values(bp)
      })
      
      try({
        temp2 <- temp
        temp2$confirmed_log_y_hat <- NA
        temp2$confirmed_log_y_hat <- confirmed_log_y_hat
        
        temp2 <- temp2 %>% 
                left_join(cdf) 
        q=paste0(p,"_",d)
        temp2 <- temp2 %>% 
                  expand(dataset, gid,geonameid, wikidata_id,t=min(temp$t):max(temp$t)) %>% #expand this to include all the t 
                  left_join(temp2) %>% 
                  mutate(date_asdate=min(date_asdate, na.rm=T)-1+t) %>% #go back interp date again
                  mutate(confirmed_log_slope_break = confirmed_log_slope_break %>% replace_na(0) %>% cumsum() ) %>%
                  fill(confirmed_log_intercept) %>%
                  fill(confirmed_log_slope) %>%
                  mutate(confirmed_log_y_hat= confirmed_log_intercept + confirmed_log_slope*t ) %>% 
                  mutate(confirmed_log_slope_percent_change = round((exp(confirmed_log_slope)-1)*100,2)) 

        temp_list[[as.character(q)]] <- temp2
      })
      #if( is.na( temp_list[[as.character(q)]]$y_hat) ) {print("error"); break}
    }
}
#"13055"
temp_df <- bind_rows(temp_list)
dim(temp_df) #bigger because we're interpolating now

# install.packages("devtools")
#devtools::install_github("tidyverse/multidplyr")

library(multidplyr)
library(dplyr, warn.conflicts = FALSE)
#cluster <- new_cluster(4)

#need to supress messages
rex_function <- function(x){
  temp=data.frame(confirmed_log_slope=x)
  tryCatch({
    #if there's an NA in x we get an error because breakpoints is one short
    prediction <- breakpoints(formula=confirmed_log_slope ~ 1, data=temp, h=3) %>% fitted.values()
    result=rep(NA, length(x) )
    result[!is.na(x)] <-prediction
    return(result)
    
  }, error=function(e){})
  
  return( rep(NA, length(x) ) )
         
}
#didn't take too long now

#library(multidplyr)
#library(dplyr, warn.conflicts = FALSE)
#cluster <- new_cluster(4)

library(tictoc)
tic()
library(strucchange)
test <- temp_df %>% head(20000)
test3 <- test %>% 
                group_by(wikidata_id) %>% 
                #partition(cluster) %>%
                arrange(date_asdate) %>%
                #mutate( confirmed_log_slope_y_hat = breakpoints(formula=confirmed_log_slope ~ 1, data=. ) %>% fitted.values() ) %>% 
                mutate( confirmed_log_slope_y_hat = rex_function(confirmed_log_slope) ) %>%  #fails on the cluster
                ungroup() #%>%
                #collect()
toc() #48 seconds for 10k #122 seconds for 20k

saveRDS(temp_df, "/media/skynet2/905884f0-7546-4273-9061-12a790830beb/rwd_github_private/NESScovid19/data_temp/lhs_long_interpolated.Rds")
LS0tCnRpdGxlOiAiVGhlIE1hY2hpbmUgTGVhcm5pbmcgZm9yIFNvY2lhbCBTY2llbmNlIEdsb2JhbCBTdWJuYXRpb25hbCBDb3ZpZCBDb3VudHMgRGF0c2V0IgpvdXRwdXQ6CiAgaHRtbF9ub3RlYm9vazoKICAgIHRvYzogeWVzCiAgICB0b2NfZmxvYXQ6IHRydWUKICAgIGNvZGVfZm9sZGluZzogaGlkZQpkYXRlOiAKYXV0aG9yOiAKYWZmaWxpYXRpb246IERpcmVjdG9yLCBNYWNoaW5lIExlYXJuaW5nIGZvciBTb2NpYWwgU2NpZW5jZSBMYWIsIENlbnRlciBmb3IgUGVhY2UgYW5kIFNlY3VyaXR5IFN0dWRpZXMsIFVuaXZlcnNpdHkgb2YgQ2FsaWZvcm5pYSBTYW4gRGllZ28KZWRpdG9yX29wdGlvbnM6IAogIGNodW5rX291dHB1dF90eXBlOiBpbmxpbmUKLS0tCgpSZXggVy4gRG91Z2xhc3MKCjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+CmJsb2NrcXVvdGUgewogICAgcGFkZGluZzogMTBweCAyMHB4OwogICAgbWFyZ2luOiAwIDAgMjBweDsKICAgIGZvbnQtc2l6ZTogMTRweDsKICAgIGJvcmRlci1sZWZ0OiA1cHggc29saWQgI2VlZTsKfQo8L3N0eWxlPgoKIyBJbnRyb2R1Y3Rpb24KCiMjIExpYnJhcnkgTG9hZHMKCmBgYHtyLHdhcm5pbmc9RkFMU0UsbWVzc2FnZT1GQUxTRSxlcnJvcj1GQUxTRSwgcmVzdWx0cz0naGlkZSd9CiNsaWJyYXJpZXMKbGlicmFyeShsdWJyaWRhdGUpCmxpYnJhcnkodGlkeXZlcnNlKQoKI2RldnRvb2xzOjppbnN0YWxsX2dpdGh1Yigicm9wZW5zY2kvVVNBYm91bmRhcmllcyIpCiNkZXZ0b29sczo6aW5zdGFsbF9naXRodWIoInJvcGVuc2NpL1VTQWJvdW5kYXJpZXNEYXRhIikKbGlicmFyeShVU0Fib3VuZGFyaWVzKSA7ICNpbnN0YWxsLnBhY2thZ2VzKCdVU0Fib3VuZGFyaWVzJykKZGF0YShzdGF0ZV9jb2RlcykKCmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KHNjYWxlcykKbGlicmFyeShnZ2hpZ2hsaWdodCkKbGlicmFyeShsdWJyaWRhdGUpCmxpYnJhcnkoUjApICAjIGNvbnNpZGVyIG1vdmluZyBhbGwgbGlicmFyeSBjb21tYW5kcyB0byB0b3AgLS0gdGhpcyBvbmUgd2FzIGluIGEgbG9vcCBiZWxvdwoKbGlicmFyeShXaWtpZGF0YVIpCmxpYnJhcnkoY291bnRyeWNvZGUpCgpsaWJyYXJ5KHVzbWFwKSA7ICMgaW5zdGFsbC5wYWNrYWdlcygndXNtYXAnKQpkYXRhKHN0YXRlcG9wKQojZGV2dG9vbHM6Omluc3RhbGxfZ2l0aHViKCJyb3BlbnNjaS9VU0Fib3VuZGFyaWVzIikKI2RldnRvb2xzOjppbnN0YWxsX2dpdGh1Yigicm9wZW5zY2kvVVNBYm91bmRhcmllc0RhdGEiKQpsaWJyYXJ5KFVTQWJvdW5kYXJpZXMpIDsgI2luc3RhbGwucGFja2FnZXMoJ1VTQWJvdW5kYXJpZXMnKQpkYXRhKHN0YXRlX2NvZGVzKQoKbGlicmFyeSh0aWR5dmVyc2UpCmxpYnJhcnkoc2YpCgpsaWJyYXJ5KGpzb25saXRlKQoKI1RoaXMgaXMgdG9vIHNsb3cgaXQncyBkb3dubG9hZGluZyBlYWNoCmxpYnJhcnkoR0FETVRvb2xzKQpsaWJyYXJ5KHN0cnVjY2hhbmdlKSA7ICNpbnN0YWxsLnBhY2thZ2VzKCdzdHJ1Y2NoYW5nZScpCmxpYnJhcnkodHNpYmJsZSkKCmxpYnJhcnkocGF0Y2h3b3JrKQoKYGBgCiMjIERhdGEgTG9hZGluZyBhbmQgQ2xlYW5pbmcKCmBgYHtyLCBmaWcud2lkdGg9MTAsIGZpZy5oZWlnaHQ9OCx3YXJuaW5nPUZBTFNFLG1lc3NhZ2U9RkFMU0UsZXJyb3I9RkFMU0UsIHJlc3VsdHM9J2hpZGUnfQoKbGlicmFyeSh0c2liYmxlKQoKbGhzX2xvbmcgPC0gcmVhZFJEUygiL21lZGlhL3NreW5ldDIvOTA1ODg0ZjAtNzU0Ni00MjczLTkwNjEtMTJhNzkwODMwYmViL3J3ZF9naXRodWJfcHJpdmF0ZS9ORVNTY292aWQxOS9kYXRhX3RlbXAvbGhzX2xvbmcuUmRzIikKI2RpbShsaHNfbG9uZykgIzE4NywzMDUKCmxoc19sb25nX2NsZWFuIDwtIGxoc19sb25nICU+JSAKICAgICAgICAgICAgICAgICAgZHBseXI6OnNlbGVjdChkYXRhc2V0LCBnaWQsZ2VvbmFtZWlkLCB3aWtpZGF0YV9pZCAsZGF0ZV9hc2RhdGUsIGNvbmZpcm1lZCwgZGVhdGhzLCB0ZXN0ZWRfcGVvcGxlLCB0ZXN0ZWRfc2FtcGxlcykgJT4lCiAgICAgICAgICAgICAgICAgIGdyb3VwX2J5KGRhdGFzZXQsIGdpZCxnZW9uYW1laWQsIHdpa2lkYXRhX2lkICxkYXRlX2FzZGF0ZSkgJT4lICNpZiB0aGUgc2FtZSBzb3VyY2UgaGFzIG11bHRpcGxlIHZhbHVlcyBvbiB0aGUgc2FtZSB0aGluZyBvbiB0aGUgc2FtZSBkYXksIG9yIGRpZmZlcmVudCB2YWx1ZXMgYWNyb3NzIHVubWVyZ2VkIG9icywgdGhlbiB0YWtlIHRoZSBtYXgKICAgICAgICAgICAgICAgICAgc3VtbWFyaXNlX2FsbChtYXgsIG5hLnJtPVQpICU+JSAKICAgICAgICAgICAgICAgICAgdW5ncm91cCgpICU+JQogICAgICAgICAgICAgICAgICBtdXRhdGVfaWYoaXMubnVtZXJpYywgbGlzdCh+bmFfaWYoLiwgLUluZikpKSAlPiUKICAgICAgICAgICAgICAgICAgbXV0YXRlX2lmKGlzLm51bWVyaWMsIGxpc3Qofm5hX2lmKC4sIEluZikpKSAlPiUKICAgICAgICAgICAgICAgICAgbXV0YXRlKGRhdGFzZXRfZ2lkX2dlb25hbWVpZF93aWtpZGF0YV9pZD0gcGFzdGUoZGF0YXNldCxnaWQsZ2VvbmFtZWlkLCB3aWtpZGF0YV9pZCwgc2VwPSJfIikgICkgJT4lCiAgICAgICAgICAgICAgICAgIG11dGF0ZShnaWRfZ2VvbmFtZWlkX3dpa2lkYXRhX2lkPSBwYXN0ZShnaWQsZ2VvbmFtZWlkLCB3aWtpZGF0YV9pZCwgc2VwPSJfIikgICkgJT4lCiAgCiAgICAgICAgICAgICAgICAgIGZpbHRlcighaXMubmEoZGF0ZV9hc2RhdGUpKSAlPiUKICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICNGaXJzdCBkcm9wIGFueXRoaW5nIHRoYXQncyBuZWdhdGl2ZS4gU2hvdWxkbid0IGJlIGFueSBuZWdhdGl2ZXMuCiAgICAgICAgICAgICAgICAgIGZpbHRlcihpcy5uYShjb25maXJtZWQpIHwgY29uZmlybWVkPj0wKSAlPiUKICAgICAgICAgICAgICAgICAgZmlsdGVyKGlzLm5hKGRlYXRocykgfCBkZWF0aHM+PTApICU+JQogICAgICAgICAgICAgICAgICBmaWx0ZXIoaXMubmEodGVzdGVkX3Blb3BsZSkgfCB0ZXN0ZWRfcGVvcGxlPj0wKSAlPiUKICAgICAgICAgICAgICAgICAgZmlsdGVyKGlzLm5hKHRlc3RlZF9zYW1wbGVzKSB8IHRlc3RlZF9zYW1wbGVzPj0wKSAlPiUKICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICNUaGVuIHNldCAwcyB0byBOQSwgd2UgZG9uJ3QgdHJ1c3QgTkFzCiAgICAgICAgICAgICAgICAgIG11dGF0ZShjb25maXJtZWQ9aWZlbHNlKGNvbmZpcm1lZD09MCwgTkEsIGNvbmZpcm1lZCkpICU+JQogICAgICAgICAgICAgICAgICBtdXRhdGUoZGVhdGhzPWlmZWxzZShkZWF0aHM9PTAsIE5BLCBkZWF0aHMpKSAlPiUKICAgICAgICAgICAgICAgICAgbXV0YXRlKHRlc3RlZF9wZW9wbGU9aWZlbHNlKHRlc3RlZF9wZW9wbGU9PTAsIE5BLCB0ZXN0ZWRfcGVvcGxlKSkgJT4lCiAgICAgICAgICAgICAgICAgIG11dGF0ZSh0ZXN0ZWRfc2FtcGxlcz1pZmVsc2UodGVzdGVkX3NhbXBsZXM9PTAsIE5BLCB0ZXN0ZWRfc2FtcGxlcykpICU+JQogICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICNUaGVuIGNoZWNrIGZpcnN0IGRpZmZlcmVuY2VzIGFuZCBkcm9wIGFueXRoaW5nIHRoYXQgZG9lc24ndCB3ZWFrbHkgaW5jcmVhc2UgbW9ub3RvbmljYWxseQogICAgICAgICAgICAgICAgICBncm91cF9ieShkYXRhc2V0LCBnaWRfZ2VvbmFtZWlkX3dpa2lkYXRhX2lkKSAlPiUgCiAgICAgICAgICAgICAgICAgICAgYXJyYW5nZShkYXRlX2FzZGF0ZSkgJT4lCiAgICAgICAgICAgICAgICAgICAgbXV0YXRlKGNvbmZpcm1lZF9jdW1tYXg9Y29uZmlybWVkICU+JSByZXBsYWNlX25hKDApICU+JSAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjdW1tYXgoKSwgZGVhdGhzX2N1bW1heD1kZWF0aHMlPiUgcmVwbGFjZV9uYSgwKSAlPiUgY3VtbWF4KCksIHRlc3RlZF9wZW9wbGVfY3VtbWF4PXRlc3RlZF9wZW9wbGUlPiUgcmVwbGFjZV9uYSgwKSAlPiUgY3VtbWF4KCksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRlc3RlZF9zYW1wbGVzX2N1bW1heD10ZXN0ZWRfc2FtcGxlcyU+JSByZXBsYWNlX25hKDApICU+JSBjdW1tYXgoKSkgJT4lCiAgICAgICAgICAgICAgICAgIHVuZ3JvdXAoKSAlPiUgIAogIAogICAgICAgICAgICAgICAgICAjQWJvdXQgNGsgb2YgdGhlc2Ugb2JzZXJ2YXRpb25zIHNob3cgYSBkZWNyZWFzZSBmcm9tIG9uZSB0aW1lIHN0ZXAgdG8gdGhlIG5leHQgd2hpY2ggc3VnZ2VzdHMgZWl0aGVyIGFuIG9yaWdpbmFsIGVycm9yIG9yIGEgam9pbmluZyBlcnJvcgogICAgICAgICAgICAgICAgICAjV2UncmUgZ29pbmcgdG8gc3RyYWlnaHQgZHJvcCB0aG9zZSBvYnNlcnZhdGlvbnMgYXMgYSBjbGVhbmluZyBzdGVwCiAgICAgICAgICAgICAgICAgICN0aGlzIGlzbid0IGVub3VnaCBiZWNhdXNlIGlmIHlvdSBoYXZlIGNvbnNlY3V0aXZlIG1pc3Rha2VzIGl0J2xsIHNob3cgYSBwb3NpdGl2ZSBmZCBldmVuIGlmIGl0J3Mgbm90IGdvb2QgZW5vdWdoCiAgICAgICAgICAgICAgICAgIGZpbHRlciggKGlzLm5hKGNvbmZpcm1lZCkgfCBjb25maXJtZWQ+PWNvbmZpcm1lZF9jdW1tYXgpICYgICNuZXZlciBhbGxvdyBmb3IgYSByZXZlcnNhbAogICAgICAgICAgICAgICAgICAgICAgICAgIChpcy5uYShkZWF0aHMpIHwgZGVhdGhzPj1kZWF0aHNfY3VtbWF4KSAmICAgICAgICAjbmV2ZXIgYWxsb3cgZm9yIGEgcmV2ZXJzYWwKICAgICAgICAgICAgICAgICAgICAgICAgICAoaXMubmEodGVzdGVkX3Blb3BsZSkgfCB0ZXN0ZWRfcGVvcGxlPj10ZXN0ZWRfcGVvcGxlX2N1bW1heCkgJiAgI25ldmVyIGFsbG93IGZvciBhIHJldmVyc2FsCiAgICAgICAgICAgICAgICAgICAgICAgICAgKGlzLm5hKHRlc3RlZF9zYW1wbGVzKSB8IHRlc3RlZF9zYW1wbGVzPj10ZXN0ZWRfc2FtcGxlc19jdW1tYXgpICAjbmV2ZXIgYWxsb3cgZm9yIGEgcmV2ZXJzYWwKICAgICAgICAgICAgICAgICAgICAgICAgICApICU+JQogICN3ZSdyZSBnb2luZyB0byBnbyBvbmUgc3RlcCBmdXJ0aGVyIGFuZCByZXF1aXJlIGVpdGhlciBjb25maXJtZWQgb3IgdGVzdGVkIHRvIGJlIHN0cmljdGx5IGhpZ2hlcgogICNJbiB3b3JkcywgZHVyaW5nIGFuIGVwaXNvZGUgd2UgZG9uJ3QgYmVsaWV2ZSByZXBvcnRzIG1lYW4gIm5vIG5ldyBjYXNlcyIganVzdCBubyBuZXcgZ29vZCByZXBvcnRpbmcKICAjbWV0YWJpb3RhIGlzIHRoZSB3b3JzdCBvZmZlbmRlciBoZXJlIHNvIHJlc3RyaWN0aW5nIGl0IHRvIGp1c3QgdGhhdAogIGZpbHRlciggISgKICAgICAgICAgICAgZGF0YXNldD09Im1ldGFiaW90YSIgJiAjaXMgbWV0YWJpb3RhCiAgICAgICAgICAgICghaXMubmEoY29uZmlybWVkKSAmICAgI3dpdGggYSBub24gbWlzc2luZyBjb25maXJtZWQKICAgICAgICAgICAgICBjb25maXJtZWQ8PWNvbmZpcm1lZF9jdW1tYXggKSAjdGhhdCBpcyBlcXVhbCB0byBvciBsZXNzIHRoYW4gdGhlIGN1bXVsYXRpdmUgbWF4IHVudGlsIHRoZW4uCiAgICAgICAgICAgICkgI3JlamVjdCB0aGVzZQogICAgICAgICAgKSAlPiUgI21ldGFiaW90YSBpcyByZWFsbHkgcHJvYmxlbWF0aWMgOTAlIG9mIHdoYXQgd2UncmUgZG9pbmcgaXMgdHJ5aW5nIHRvIGFjY291bnQgZm9yIGl0CiAgCiAgI0Fsc28gcmVqZWN0IGFueSB3aGVyZSBkZWF0aHMgYXJlIGdyZWF0ZXIgdGhhbiBjb25maXJtZWQKICBmaWx0ZXIoaXMubmEoY29uZmlybWVkKSB8IGlzLm5hKGRlYXRocykgfCBjb25maXJtZWQ+PWRlYXRocykgJT4lCiAgCiAgI2Fsc28gcmVqZWN0IGFueSB3aGVyZSBjb25maXJtZWQgZG9lc24ndCB2YXJ5IAogIGdyb3VwX2J5KGdpZCAsICBnZW9uYW1laWQgLHdpa2lkYXRhX2lkKSAlPiUgI2Nob3NlIG5vdCB0byBkbyBieSBkYXRhc2V0IGJlY2F1c2UgdGVzdGluZyBkYXRhc2V0cyBtaWdodCBub3QgaGF2ZSBjb25maXJtZWQKICAgIGZpbHRlcih2YXIoY29uZmlybWVkLCBuYS5ybT1UKT4wKSAlPiUKICB1bmdyb3VwKCkKCiAgCiNkaW0obGhzX2xvbmdfY2xlYW4pICMyODEsNDY0ICMyOTIsNTgwICMyOTkyMTMgIzE4MSw1NjMKCnNhdmVSRFMobGhzX2xvbmdfY2xlYW4sCiAgICAgICAgIi9tZWRpYS9za3luZXQyLzkwNTg4NGYwLTc1NDYtNDI3My05MDYxLTEyYTc5MDgzMGJlYi9yd2RfZ2l0aHViX3ByaXZhdGUvTkVTU2NvdmlkMTkvZGF0YV90ZW1wL2xoc19sb25nX2NsZWFuZC5SZHMiKQoKYGBgCgpTdW1tYXJ5IFN0YXRpc3RpY3Mgb2YgT3VyIERhdGEKCmBgYHtyfQpwcmludCgiTnVtYmVyIG9mIG9ic2VydmF0aW9ucyIpCmRpbShsaHNfbG9uZ19jbGVhbikKCnByaW50KCJOdW1iZXIgb2YgbG9jYXRpb25zIikKbGhzX2xvbmdfY2xlYW4kd2lraWRhdGFfaWQgJT4lIHVuaXF1ZSgpICU+JSBsZW5ndGgoKSAjMywzNzMKCnByaW50KCJOdW1iZXIgb2YgRGF5cyIpCmxoc19sb25nX2NsZWFuJGRhdGVfYXNkYXRlICU+JSB1bmlxdWUoKSAlPiUgbGVuZ3RoKCkgIzExMwoKbGlicmFyeShEVCkgI2h0dHBzOi8vcnN0dWRpby5naXRodWIuaW8vRFQvCmxoc19sb25nX2NsZWFuICU+JSBjb3VudChkYXRhc2V0KSAlPiUgYXJyYW5nZSgtbikgJT4lIERUOjpkYXRhdGFibGUob3B0aW9ucyA9IGxpc3QocGFnZUxlbmd0aCA9IDIwLCBhdXRvV2lkdGggPSBUUlVFKSkKCiNsaWJyYXJ5KGd0KQojbGhzX2xvbmdfY2xlYW4gJT4lIGNvdW50KGRhdGFzZXQpICU+JSBhcnJhbmdlKC1uKSAlPiUgZ3QoKSAlPiUgCiMgdGFiX2hlYWRlcigKIyAgICB0aXRsZSA9IG1kKCJMb2NhdGlvbi1EYXlzIGJ5IERhdGFzZXQiKSMsCiMgICAgI3N1YnRpdGxlID0gIk51bWJlciBvZiBEYXlzIHdpdGggRGF0YSBieSBEYXRhc2V0IgojICApICU+JQojICBmbXRfbWlzc2luZyggY29sdW1ucz1ldmVyeXRoaW5nKCksIHJvd3M9TlVMTCxtaXNzaW5nX3RleHQgPSAwKQoKYGBgCgoKIyBTcGF0aWFsIFZhcmlhdGlvbiBpbiBEYXRhIEF2YWlsYWJpbGl0eQoKIyMgQ291bnRyeSBMZXZlbCBEYXRhIEF2YWlsYWJpbGl0eQoKYGBge3IsIGZpZy53aWR0aD0xMiwgZmlnLmhlaWdodD0xMix3YXJuaW5nPUZBTFNFLG1lc3NhZ2U9RkFMU0UsZXJyb3I9RkFMU0UsIHJlc3VsdHM9J2hpZGUnfQoKI2dhZG0zNiA9IHN0X3JlYWQoIi9tZWRpYS9za3luZXQyLzkwNTg4NGYwLTc1NDYtNDI3My05MDYxLTEyYTc5MDgzMGJlYi9yd2RfZ2l0aHViX3ByaXZhdGUvTkVTU2dhZG0vZGF0YV9pbi9nYWRtMzZfZ3BrZy9nYWRtMzYuZ3BrZyIpCiNzdF9sYXllcnMoIi9tZWRpYS9za3luZXQyLzkwNTg4NGYwLTc1NDYtNDI3My05MDYxLTEyYTc5MDgzMGJlYi9yd2RfZ2l0aHViX3ByaXZhdGUvTkVTU2NvdmlkMTkvZGF0YV90ZW1wL2dhZG0zNl9ieWNvdW50cnkvZ2FkbTM2X2xldmVsc19ncGtnL2dhZG0zNl9sZXZlbHMuZ3BrZyIpCmdhZG0zNl9sZXZlbHNfMCA9IHN0X3JlYWQoIi9tZWRpYS9za3luZXQyLzkwNTg4NGYwLTc1NDYtNDI3My05MDYxLTEyYTc5MDgzMGJlYi9yd2RfZ2l0aHViX3ByaXZhdGUvTkVTU2NvdmlkMTkvZGF0YV90ZW1wL2dhZG0zNl9ieWNvdW50cnkvZ2FkbTM2X2xldmVsc19ncGtnL2dhZG0zNl9sZXZlbHMuZ3BrZyIsIGxheWVyPSJsZXZlbDAiKSAgJT4lCiAgICAgICAgICAgICAgICAgIHN0X3NpbXBsaWZ5KHByZXNlcnZlVG9wb2xvZ3kgPSBGQUxTRSwgZFRvbGVyYW5jZSA9MC4xKSAjICAwLjAyNSB0aGlzIGlzIHN1cHBvc2VkbHkgYnJva2VuIHVwIGJ5IDYgbGV2ZWxzIGFuZCBzbyBzaG91bGQgaGF2ZSB1LnMuIAoKI3Bsb3QoZ2FkbTM2X2xldmVsc18wKQojZGltKGdhZG0zNl9sZXZlbHNfMF9zZiRzZikKI2dhZG1fcGxvdChnYWRtMzZfbGV2ZWxzXzBfc2YpCmxoc19sb25nX3BsYWNlX3NvdXJjZXMgPC0gbGhzX2xvbmcgICU+JSBkcGx5cjo6c2VsZWN0KGdpZCwgICBnZW9uYW1laWQsIHdpa2lkYXRhX2lkLCBkYXRhc2V0KSAlPiUgCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGdyb3VwX2J5KGdpZCwgIGdlb25hbWVpZCwgd2lraWRhdGFfaWQpICU+JSBjb3VudChkYXRhc2V0KSAlPiUKICAgICAgICAgICAgICAgICAgICAgICAgICAgZ3JvdXBfYnkoZ2lkLCAgZ2VvbmFtZWlkLCB3aWtpZGF0YV9pZCkgJT4lCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHN1bW1hcmlzZShkYXRhc2V0c19uPW4oKSkgCgpwMCA8LSBnYWRtMzZfbGV2ZWxzXzAgJT4lIAogICAgICBsZWZ0X2pvaW4obGhzX2xvbmdfcGxhY2Vfc291cmNlcyAlPiUgZHBseXI6OnNlbGVjdChnaWQ9Z2lkLCBkYXRhc2V0c19uKSAlPiUgIGxlZnRfam9pbiggZ2FkbTM2X2xldmVsc18wICU+JSBhcy5kYXRhLmZyYW1lKCkgJT4lIGRwbHlyOjpzZWxlY3QoZ2lkPUdJRF8wLCBOQU1FXzApICAlPiUgZGlzdGluY3QoKSAgKQogICAgICAgICAgICAgICAgKSAlPiUKICAgICAgI3JlcGxhY2VfbmEobGlzdChkYXRhc2V0c19uID0gMCkpICU+JSAKICAgICAgZ2dwbG90KCkgKyBnZW9tX3NmKGFlcyhmaWxsID0gZGF0YXNldHNfbikpICsKICAgICAgc2NhbGVfZmlsbF9ncmFkaWVudChsb3c9InJlZCIsIGhpZ2g9ImdyZWVuIikgKwogICAgICB0aGVtZV9idygpIApgYGAKCgoKYGBge3IsIGZpZy53aWR0aD0xMiwgZmlnLmhlaWdodD02LHdhcm5pbmc9RkFMU0UsbWVzc2FnZT1GQUxTRSxlcnJvcj1GQUxTRX0KcDAgKyBnZ3RpdGxlKCJDb3ZpZCBDb3VudCBEYXRhIEF2YWlsYWJpbGl0eSBhdCB0aGUgQ291bnRyeSBMZXZlbCIpCmBgYAoKYGBge3J9CnRlbXAgPC0gZ2FkbTM2X2xldmVsc18wICU+JQogICBsZWZ0X2pvaW4oCiAgIGxoc19sb25nICAlPiUgY291bnQoZ2lkLCBkYXRhc2V0KSAlPiUgcmVuYW1lKEdJRF8wPWdpZCkgI3RoZXJlIGFyZSBzdGlsbCBkdXBlIGdlb25hbWVzIHdpa2lkYXRhIHRvIGdpZCBtYXRjaGVzIHRoYXQgbmVlZCB0byBiZSBmaXhlZCBnZW9uYW1laWQsIHdpa2lkYXRhX2lkLCAKKSAKCnRlbXBfd2lkZSA8LSB0ZW1wICU+JSBhcy5kYXRhLmZyYW1lKCkgJT4lIGRwbHlyOjpzZWxlY3QoQ291bnRyeT1OQU1FXzAsIGRhdGFzZXQsIG4pICU+JSBkaXN0aW5jdCgpICU+JSBwaXZvdF93aWRlciggaWRfY29scyA9IENvdW50cnksIG5hbWVzX2Zyb20gPSBkYXRhc2V0LAogIHZhbHVlc19mcm9tID0gbiwgdmFsdWVzX2ZpbGwgPSBOVUxMLCB2YWx1ZXNfZm4gPSBOVUxMKSAKCnRlbXBfd2lkZSAlPiUgRFQ6OmRhdGF0YWJsZShvcHRpb25zID0gbGlzdChwYWdlTGVuZ3RoID0gMjAsIGF1dG9XaWR0aCA9IFRSVUUpKQoKI2luc3RhbGwucGFja2FnZXMoJ2d0JykKI2xpYnJhcnkoZ3QpCiN0ZW1wX3dpZGUgJT4lIGd0KCkgJT4lIAojIHRhYl9oZWFkZXIoCiMgICAgdGl0bGUgPSBtZCgiRGF0YSBBdmFpbGFiaWxpdHkgYnkgQ291bnRyeSIpLAojICAgIHN1YnRpdGxlID0gIk51bWJlciBvZiBEYXlzIHdpdGggRGF0YSBieSBEYXRhc2V0IgojICApICU+JQojICBmbXRfbWlzc2luZyggY29sdW1ucz1ldmVyeXRoaW5nKCksIHJvd3M9TlVMTCxtaXNzaW5nX3RleHQgPSAwKQoKYGBgCgojIyBTdGF0ZS9Qcm92aW5jZSBMZXZlbCBEYXRhIEF2YWlsYWJpbGl0eQoKCmBgYHtyLCBmaWcud2lkdGg9MTIsIGZpZy5oZWlnaHQ9MTIsd2FybmluZz1GQUxTRSxtZXNzYWdlPUZBTFNFLGVycm9yPUZBTFNFLCByZXN1bHRzPSdoaWRlJ30KZ2FkbTM2X2xldmVsc18xID0gc3RfcmVhZCgiL21lZGlhL3NreW5ldDIvOTA1ODg0ZjAtNzU0Ni00MjczLTkwNjEtMTJhNzkwODMwYmViL3J3ZF9naXRodWJfcHJpdmF0ZS9ORVNTY292aWQxOS9kYXRhX3RlbXAvZ2FkbTM2X2J5Y291bnRyeS9nYWRtMzZfbGV2ZWxzX2dwa2cvZ2FkbTM2X2xldmVscy5ncGtnIiwgbGF5ZXI9ImxldmVsMSIpICAlPiUKICBzdF9zaW1wbGlmeShwcmVzZXJ2ZVRvcG9sb2d5ID0gRkFMU0UsIGRUb2xlcmFuY2UgPTAuMSkgIyAgMC4wMjUgdGhpcyBpcyBzdXBwb3NlZGx5IGJyb2tlbiB1cCBieSA2IGxldmVscyBhbmQgc28gc2hvdWxkIGhhdmUgdS5zLiAKCgpwMSA8LSBnYWRtMzZfbGV2ZWxzXzEgJT4lIAogIGxlZnRfam9pbihsaHNfbG9uZ19wbGFjZV9zb3VyY2VzICU+JSBkcGx5cjo6c2VsZWN0KGdpZD1naWQsIGRhdGFzZXRzX24pICU+JSAgbGVmdF9qb2luKCBnYWRtMzZfbGV2ZWxzXzEgJT4lIGFzLmRhdGEuZnJhbWUoKSAlPiUgZHBseXI6OnNlbGVjdChnaWQ9R0lEXzEsIE5BTUVfMSkgJT4lIGRpc3RpbmN0KCkgICkKICApICU+JQogICNyZXBsYWNlX25hKGxpc3QoZGF0YXNldHNfbiA9IDApKSAlPiUgCiAgZ2dwbG90KCkgKyBnZW9tX3NmKGFlcyhmaWxsID0gZGF0YXNldHNfbikpICsKICBzY2FsZV9maWxsX2dyYWRpZW50KGxvdz0icmVkIiwgaGlnaD0iZ3JlZW4iKSArCiAgdGhlbWVfYncoKSAKYGBgCgpgYGB7ciwgZmlnLndpZHRoPTEyLCBmaWcuaGVpZ2h0PTYsd2FybmluZz1GQUxTRSxtZXNzYWdlPUZBTFNFLGVycm9yPUZBTFNFfQpwMQpgYGAKCmBgYHtyfQp0ZW1wIDwtIGdhZG0zNl9sZXZlbHNfMSAlPiUKICAgbGVmdF9qb2luKAogICBsaHNfbG9uZyAgJT4lIGNvdW50KGdpZCwgZGF0YXNldCkgJT4lIHJlbmFtZShHSURfMT1naWQpICN0aGVyZSBhcmUgc3RpbGwgZHVwZSBnZW9uYW1lcyB3aWtpZGF0YSB0byBnaWQgbWF0Y2hlcyB0aGF0IG5lZWQgdG8gYmUgZml4ZWQgZ2VvbmFtZWlkLCB3aWtpZGF0YV9pZCwgCikgCgp0ZW1wX3dpZGUgPC0gdGVtcCAlPiUgYXMuZGF0YS5mcmFtZSgpICU+JSBkcGx5cjo6c2VsZWN0KENvdW50cnk9TkFNRV8wLCBBZG1pbjE9TkFNRV8xLCBkYXRhc2V0LCBuKSAlPiUgZGlzdGluY3QoKSAlPiUgcGl2b3Rfd2lkZXIoIGlkX2NvbHMgPSBDb3VudHJ5OkFkbWluMSwgbmFtZXNfZnJvbSA9IGRhdGFzZXQsCiAgdmFsdWVzX2Zyb20gPSBuLCB2YWx1ZXNfZmlsbCA9IE5VTEwsIHZhbHVlc19mbiA9IE5VTEwpICU+JSBtdXRhdGUodG90YWwgPSByb3dTdW1zKC5bLWMoMSwyKV0sIG5hLnJtID0gVCkpCgp0ZW1wX3dpZGUgJT4lIGZpbHRlcih0b3RhbD4wKSAlPiUgRFQ6OmRhdGF0YWJsZShvcHRpb25zID0gbGlzdChwYWdlTGVuZ3RoID0gMTAsIGF1dG9XaWR0aCA9IFRSVUUpKQoKYGBgCgojIyBDb3VudHkgRGlzdHJpY3QgTGV2ZWwgRGF0YSBBdmFpbGFiaWxpdHkKCmBgYHtyLCBmaWcud2lkdGg9MTIsIGZpZy5oZWlnaHQ9MTIsd2FybmluZz1GQUxTRSxtZXNzYWdlPUZBTFNFLGVycm9yPUZBTFNFLCByZXN1bHRzPSdoaWRlJ30KZ2FkbTM2X2xldmVsc18yID0gc3RfcmVhZCgiL21lZGlhL3NreW5ldDIvOTA1ODg0ZjAtNzU0Ni00MjczLTkwNjEtMTJhNzkwODMwYmViL3J3ZF9naXRodWJfcHJpdmF0ZS9ORVNTY292aWQxOS9kYXRhX3RlbXAvZ2FkbTM2X2J5Y291bnRyeS9nYWRtMzZfbGV2ZWxzX2dwa2cvZ2FkbTM2X2xldmVscy5ncGtnIiwgbGF5ZXI9ImxldmVsMiIpICAlPiUKICBzdF9zaW1wbGlmeShwcmVzZXJ2ZVRvcG9sb2d5ID0gRkFMU0UsIGRUb2xlcmFuY2UgPSAwLjAwMSkgIyAgMC4wMjUgdGhpcyBpcyBzdXBwb3NlZGx5IGJyb2tlbiB1cCBieSA2IGxldmVscyBhbmQgc28gc2hvdWxkIGhhdmUgdS5zLiBJIGhhdmUgdG8ga2VlcCBzaHJpbmtpbmcgaXQgc28gbWlzaXNuZyBnb2VzIHRvIHplcm8gCgpwMiA8LSBnYWRtMzZfbGV2ZWxzXzIgJT4lIAogIGxlZnRfam9pbihsaHNfbG9uZ19wbGFjZV9zb3VyY2VzICU+JSBkcGx5cjo6c2VsZWN0KGdpZD1naWQsIGRhdGFzZXRzX24pICU+JSAgbGVmdF9qb2luKCBnYWRtMzZfbGV2ZWxzXzIgJT4lIGFzLmRhdGEuZnJhbWUoKSAlPiUgZHBseXI6OnNlbGVjdChnaWQ9R0lEXzIsIE5BTUVfMikgJT4lIGRpc3RpbmN0KCkgICkKICApICU+JQogICNyZXBsYWNlX25hKGxpc3QoZGF0YXNldHNfbiA9IDApKSAlPiUgCiAgZ2dwbG90KCkgKyBnZW9tX3NmKGFlcyhmaWxsID0gZGF0YXNldHNfbiksbHdkID0gMCkgKwogIHNjYWxlX2ZpbGxfZ3JhZGllbnQobG93PSJibHVlIiwgaGlnaD0icmVkIikgKwogIHRoZW1lX2J3KCkgCmBgYAoKYGBge3IsIGZpZy53aWR0aD0xMiwgZmlnLmhlaWdodD02LHdhcm5pbmc9RkFMU0UsbWVzc2FnZT1GQUxTRSxlcnJvcj1GQUxTRX0KCnAyCgpgYGAKCgpgYGB7cn0KdGVtcCA8LSBnYWRtMzZfbGV2ZWxzXzIgJT4lCiAgIGxlZnRfam9pbigKICAgbGhzX2xvbmcgICU+JSBjb3VudChnaWQsIGRhdGFzZXQpICU+JSByZW5hbWUoR0lEXzI9Z2lkKSAjdGhlcmUgYXJlIHN0aWxsIGR1cGUgZ2VvbmFtZXMgd2lraWRhdGEgdG8gZ2lkIG1hdGNoZXMgdGhhdCBuZWVkIHRvIGJlIGZpeGVkIGdlb25hbWVpZCwgd2lraWRhdGFfaWQsIAopIAoKdGVtcF93aWRlIDwtIHRlbXAgJT4lIGFzLmRhdGEuZnJhbWUoKSAlPiUgZHBseXI6OnNlbGVjdChDb3VudHJ5PU5BTUVfMCwgQWRtaW4xPU5BTUVfMSwgQWRtaW4yPU5BTUVfMiwgZGF0YXNldCwgbikgJT4lIGRpc3RpbmN0KCkgJT4lIHBpdm90X3dpZGVyKCBpZF9jb2xzID0gQ291bnRyeTpBZG1pbjIsIG5hbWVzX2Zyb20gPSBkYXRhc2V0LAogIHZhbHVlc19mcm9tID0gbiwgdmFsdWVzX2ZpbGwgPSBOVUxMLCB2YWx1ZXNfZm4gPSBOVUxMKSAlPiUgbXV0YXRlKHRvdGFsID0gcm93U3VtcyguWy1jKDEsMiwzKV0sIG5hLnJtID0gVCkpCgp0ZW1wX3dpZGUgJT4lIGZpbHRlcih0b3RhbD4wKSAlPiUgRFQ6OmRhdGF0YWJsZShvcHRpb25zID0gbGlzdChwYWdlTGVuZ3RoID0gMTAsIGF1dG9XaWR0aCA9IFRSVUUpKQoKYGBgCgojIyBDb3VudHJ5IERhdGEgQXZhaWxhYmlsaXR5IG9mIFRlc3RpbmcKCmBgYHtyfQoKbGhzX2xvbmdfcGxhY2Vfc291cmNlc190ZXN0aW5nIDwtIGxoc19sb25nICAlPiUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRwbHlyOjpzZWxlY3QoZ2lkLCAgZ2VvbmFtZWlkLCB3aWtpZGF0YV9pZCwgZGF0ZV9hc2RhdGUsIGNvbmZpcm1lZCwgdGVzdGVkX3Blb3BsZSwgdGVzdGVkX3NhbXBsZXMpICU+JQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ3JvdXBfYnkoZ2lkLCAgZ2VvbmFtZWlkLCB3aWtpZGF0YV9pZCwgZGF0ZV9hc2RhdGUpICU+JSAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG11dGF0ZV9pZihpcy5udW1lcmljLCBtYXgsIG5hLnJtPVQpICU+JQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsdGVyKCFkdXBsaWNhdGVkKGRhdGVfYXNkYXRlKSkgJT4lCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB1bmdyb3VwKCkgJT4lCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtdXRhdGVfaWYoaXMubnVtZXJpYywgbGlzdCh+bmFfaWYoLiwgLUluZikpKSAlPiUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG11dGF0ZV9pZihpcy5udW1lcmljLCBsaXN0KH5uYV9pZiguLCBJbmYpKSkgJT4lCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtdXRhdGUocGVyY2VudF9vZl9kYXlzX3dpdGhvdXRfdGVzdGluZz0haXMubmEoZGF0ZV9hc2RhdGUpICYgKGlzLm5hKHRlc3RlZF9wZW9wbGUpICYgaXMubmEodGVzdGVkX3NhbXBsZXMpICApKSAlPiUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ3JvdXBfYnkoZ2lkLCAgZ2VvbmFtZWlkLCB3aWtpZGF0YV9pZCkgJT4lIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3VtbWFyaXNlKAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBlcmNlbnRfb2ZfZGF5c193aXRob3V0X3Rlc3Rpbmc9c3VtKHBlcmNlbnRfb2ZfZGF5c193aXRob3V0X3Rlc3RpbmcsIG5hLnJtPVQpL24oKQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICkgJT4lCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtdXRhdGUocGVyY2VudF9vZl9kYXlzX3dpdGhfdGVzdGluZz0gMS1wZXJjZW50X29mX2RheXNfd2l0aG91dF90ZXN0aW5nKSAKCgpwMF90ZXN0aW5nIDwtIGdhZG0zNl9sZXZlbHNfMCAlPiUgCiAgICAgIGxlZnRfam9pbihsaHNfbG9uZ19wbGFjZV9zb3VyY2VzX3Rlc3RpbmcgJT4lIGRwbHlyOjpzZWxlY3QoZ2lkPWdpZCwgcGVyY2VudF9vZl9kYXlzX3dpdGhfdGVzdGluZykgJT4lICBsZWZ0X2pvaW4oIGdhZG0zNl9sZXZlbHNfMCAlPiUgYXMuZGF0YS5mcmFtZSgpICU+JSBkcGx5cjo6c2VsZWN0KGdpZD1HSURfMCwgTkFNRV8wKSAgJT4lIGRpc3RpbmN0KCkgICkKICAgICAgICAgICAgICAgICkgJT4lCiAgICAgICNyZXBsYWNlX25hKGxpc3QoZGF0YXNldHNfbiA9IDApKSAlPiUgCiAgICAgIGdncGxvdCgpICsgZ2VvbV9zZihhZXMoZmlsbCA9IHBlcmNlbnRfb2ZfZGF5c193aXRoX3Rlc3RpbmcpKSArCiAgICAgIHNjYWxlX2ZpbGxfZ3JhZGllbnQobG93PSJyZWQiLCBoaWdoPSJncmVlbiIpICsKICAgICAgdGhlbWVfYncoKSArIGdndGl0bGUoIlBlcmNlbnQgb2YgRGF5cyB3aXRoIFRlc3RpbmcgY291bnRzIikKYGBgCgpgYGB7ciwgZmlnLndpZHRoPTEyLCBmaWcuaGVpZ2h0PTYsd2FybmluZz1GQUxTRSxtZXNzYWdlPUZBTFNFLGVycm9yPUZBTFNFfQpwMF90ZXN0aW5nCmBgYApgYGB7cix3YXJuaW5nPUZBTFNFLG1lc3NhZ2U9RkFMU0UsZXJyb3I9RkFMU0UsIHJlc3VsdHM9J2hpZGUnfQpwMV90ZXN0aW5nIDwtIGdhZG0zNl9sZXZlbHNfMSAlPiUgCiAgbGVmdF9qb2luKGxoc19sb25nX3BsYWNlX3NvdXJjZXNfdGVzdGluZyAlPiUgZHBseXI6OnNlbGVjdChnaWQ9Z2lkLCBwZXJjZW50X29mX2RheXNfd2l0aF90ZXN0aW5nKSAlPiUgIGxlZnRfam9pbiggZ2FkbTM2X2xldmVsc18xICU+JSBhcy5kYXRhLmZyYW1lKCkgJT4lIGRwbHlyOjpzZWxlY3QoZ2lkPUdJRF8xLCBOQU1FXzEpICU+JSBkaXN0aW5jdCgpICApCiAgKSAlPiUKICAjcmVwbGFjZV9uYShsaXN0KGRhdGFzZXRzX24gPSAwKSkgJT4lIAogIGdncGxvdCgpICsgZ2VvbV9zZihhZXMoZmlsbCA9IHBlcmNlbnRfb2ZfZGF5c193aXRoX3Rlc3RpbmcpKSArCiAgc2NhbGVfZmlsbF9ncmFkaWVudChsb3c9InJlZCIsIGhpZ2g9ImdyZWVuIikgKwogIHRoZW1lX2J3KCkgICsgZ2d0aXRsZSgiUGVyY2VudCBvZiBEYXlzIHdpdGggVGVzdGluZyBjb3VudHMiKQpgYGAKCmBgYHtyLCBmaWcud2lkdGg9MTIsIGZpZy5oZWlnaHQ9Nix3YXJuaW5nPUZBTFNFLG1lc3NhZ2U9RkFMU0UsZXJyb3I9RkFMU0V9CnAxX3Rlc3RpbmcKYGBgCgojIERhdGEgQXZhaWxhYmlsaXR5IGFuZCBJbnRlcnBvbGF0aW9uIG92ZXIgVGltZQoKYGBge3Isd2FybmluZz1GQUxTRSxtZXNzYWdlPUZBTFNFLGVycm9yPUZBTFNFLCByZXN1bHRzPSdoaWRlJ30KCiN0ZXN0IDwtIGxoc19sb25nICU+JSBncm91cF9ieShkYXRhc2V0LCBnaWQsIGdlb25hbWVpZCwgd2lraWRhdGFfaWQsIGRhdGVfYXNkYXRlKSAlPiUgc3VtbWFyaXplKG49bigpKQoKYWxsX25hIDwtIGZ1bmN0aW9uKHgpIGFueSghaXMubmEoeCkpICNodHRwczovL2ludGVsbGlwYWF0LmNvbS9jb21tdW5pdHkvMTI5OTkvcmVtb3ZlLWNvbHVtbnMtZnJvbS1kYXRhZnJhbWUtd2hlcmUtYWxsLXZhbHVlcy1hcmUtbmEKCiNiaW5nIGxvb2tzIG9mZiBieSBhIGRheSBmcm9tIHRoZSBvdGhlciBvbmVzCmxoc193aWRlX3Fjb2RlIDwtIGxoc19sb25nICU+JSAKICAgICAgICAgICAgICAgICAgZmlsdGVyKCFpcy5uYSh3aWtpZGF0YV9pZCkgJiAhaXMubmEoZGF0ZV9hc2RhdGUpKSAlPiUKICAgICAgICAgICAgICAgICAgZ3JvdXBfYnkoZ2lkLCBnZW9uYW1laWQsIHdpa2lkYXRhX2lkLCBkYXRlX2FzZGF0ZSkgJT4lICBtdXRhdGUoY29uZmlybWVkX3Zhcj12YXIoY29uZmlybWVkLCBuYS5ybT1UKSwgZGVhdGhzX3Zhcj12YXIoZGVhdGhzLCBuYS5ybT1UKSkgJT4lIHVuZ3JvdXAoKSAlPiUKICAgICAgICAgICAgICAgICAgZHBseXI6OnNlbGVjdChkYXRhc2V0LCBnaWQsIGdlb25hbWVpZCwgd2lraWRhdGFfaWQsIGRhdGVfYXNkYXRlLGNvbmZpcm1lZCwgZGVhdGhzLCB0ZXN0ZWRfc2FtcGxlcywgdGVzdGVkX3Blb3BsZSkgJT4lCiAgICAgICAgICAgICAgICAgIGdyb3VwX2J5KGRhdGFzZXQsIGdpZCwgZ2VvbmFtZWlkLCB3aWtpZGF0YV9pZCwgZGF0ZV9hc2RhdGUpICU+JSAgc3VtbWFyaXNlX2lmKGlzLm51bWVyaWMsbWF4LG5hLnJtPVQpICU+JSB1bmdyb3VwKCkgJT4lICN0aGlzIGlzIGEgaGFjaywgd2Ugc2hvdWxkIGhhdmUgZHVwZXMgd2l0aGluIGRhdGFzZXRzCiAgICAgICAgICAgICAgICAgIHBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSBkYXRhc2V0LCB2YWx1ZXNfZnJvbSA9IGMoY29uZmlybWVkLCBkZWF0aHMsIHRlc3RlZF9zYW1wbGVzLCB0ZXN0ZWRfcGVvcGxlKSApICU+JSAKICAgICAgICAgICAgICAgICAgbXV0YXRlX2lmKGlzLm51bWVyaWMsIGxpc3Qofm5hX2lmKGFicyguKSwgSW5mKSkpICU+JSAjaHR0cHM6Ly9zdGFja292ZXJmbG93LmNvbS9xdWVzdGlvbnMvMTIxODg1MDkvY2xlYW5pbmctaW5mLXZhbHVlcy1mcm9tLWFuLXItZGF0YWZyYW1lCiAgICAgICAgICAgICAgICAgIHNlbGVjdF9pZihhbGxfbmEpIAoKZGltKGxoc193aWRlX3Fjb2RlKSAjODIsMTU3IDgyayBwbGFjZS9kYXkgb2JzZXJ2YXRpb25zCgpsZW5ndGgodW5pcXVlKGxoc193aWRlX3Fjb2RlJHdpa2lkYXRhX2lkKSkgIzM2OTcgI2FsbW9zdCA0ayAKCnRlc3QgPC0gbGhzX3dpZGVfcWNvZGUgJT4lIGRwbHlyOjpzZWxlY3Qoc3RhcnRzX3dpdGgoImNvbmZpcm1lZCIpKSAlPiUgZGlzdGluY3QoKSAKI2Nvcih0ZXN0LCB1c2U9InBhaXJ3aXNlLmNvbXBsZXRlLm9icyIpCgpsaHNfbG9uZ19tZWRpYW4gPC0gbGhzX2xvbmcgJT4lIGdyb3VwX2J5KGdpZCwgZ2VvbmFtZWlkLCB3aWtpZGF0YV9pZCwgZGF0ZV9hc2RhdGUpICU+JSBzdW1tYXJpemVfaWYoaXMubnVtZXJpYywgbWVkaWFuLCBuYS5ybT1UKSAlPiUgZHBseXI6OnNlbGVjdCgtZW5kc193aXRoKCJfZmQiKSkgJT4lICN3ZSB0YWtlIHRoZSBtZWRpYW4gYWNyb3NzIG9ic2VydmF0aW9ucwogICAgICAgICAgICAgICAgICAgbXV0YXRlKENGUj1kZWF0aHMvY29uZmlybWVkKQojZGltKGxoc19sb25nX21lZGlhbikKI3N1bW1hcnkobGhzX2xvbmdfbWVkaWFuKQpgYGAKCkhlcmUgd2UgZG8gdGhlIGFjdHVhbCBpbnRlcnBvbGF0aW9uLiBGb3IgZWFjaCBpbmRpdmlkdWFsIGxvY2F0aW9uLWRhdGFzZXQsIHdlIGZpdCBhIHBpZWNld2lzZSBsaW5lYXIgbW9kZWwgb3ZlciB0aW1lLCBhbmQgdGhlbiB1c2UgdGhhdCB0byBhdmVyYWdlIG92ZXIgZGF5IHRvIGRheSBub2lzZSBhbmQgaW50ZXJwb2xhdGUgYmV0d2VlbiBvYnNlcnZhdGlvbnMuIEJlY2F1c2UgdGhpcyBpcyBpbiBsb2cgc3BhY2UsIHRoZSBzbG9wZSBvZiB0aGF0IGxpbmUgaXMgdGhlIGRheSBvbiBkYXkgcGVyY2VudCBpbmNyZWFzZSBpbiB0aGUgY291bnQuIFdlIGZpbmlzaCBieSBmaXR0aW5nIGEgcGllY2V3aXNlIGludGVyY2VwdCBtb2RlbCB0byB0aG9zZSBzbG9wZXMgdG8gZ2V0IGEgc2luZ2xlIGRhaWx5IGVzdGltYXRlIG9mIGhvdyBtdWNoIHRoZSBjb3VudCBpcyBpbmNyZWFzaW5nLiBEYXRhc2V0cyBhcmUgYWJsZSB0byBkaXNhZ3JlZSBpbiBsb3RzIG9mIGRpZmZlcmVudCB3YXlzIGFuZCB3ZSBzdGlsbCByZWNvdmVyIGEgY29ycmVjdCByYXRlIG9mIGNoYW5nZS4KCiMjIEludGVycG9sYXRpb24gb2YgQ291bnRzCgpUbyBlYWNoIGluZGl2aWR1YWwgZGF0YXNldC1sb2NhdGlvbiBzZXJpZXMsIHdlIGZpdCBhIHBpZWNld2lzZSBsaW5lYXIgdHJlbmQuIEVhY2ggc2VnbWVudCBpcyByZXF1aXJlZCB0byBoYXZlIGF0IGxlYXN0IDMgb2JzZXJ2YXRpb25zLCBidXQgb3RoZXJ3aXNlIHdlIG1ha2Ugbm8gb3RoZXIgY29uc3RyYWludHMuIFRoaXMgYWxsb3dzIHVzIHRvIGZsZXhpYmx5IGZpdCBsaW5lYXIgc2VnbWVudHMgYXMgd2VsbCBhcyB0aWdodCBjdXJ2ZXMuIFdlIGFsc28gYWxsb3cgZm9yIHN0cnVjdHVyYWwgYnJlYWtzIHdoZXJlIHRoZSBzZXJpZXMgc3RvcHMsIGhhcyBhIHN0cnVjdHVyYWwgc2hpZnQgdXAgb3IgZG93biBiZWNhdXNlIHNheSBhIGNoYW5nZSBpbiByZXBvcnRpbmcgcnVsZXMsIGJ1dCBvdGhlciB0aGVuIG90aGVyd2lzZSBjb250aW51ZXMgYXMgbm9ybWFsLiBXZSB0YWtlIHRoZSBsaW5lYXIgdHJlbmQgZml0IGFzIG91ciBiZXN0IGVzdGltYXRlIGF0IGVhY2ggcG9pbnQuIFRoaXMgYXZlcmFnZXMgb3ZlciBkYXkgdG8gZGF5IG5vaXNlLCBlLmcuIHVuZGVyIHJlcG9ydGluZyBvbiB0aGUgd2Vla2VuZC4gSXQgYWxzbyBhbGxvd3MgdXMgdG8gaW50ZXJwb2xhdGUgYmV0d2VlbiBvYnNlcnZhdGlvbnMgd2hlcmUgdGhlcmUgaXMgbWlzc2luZ25lc3MgaW4gdGhlIHNlcmllcyBidXQgd2UgaGF2ZSByZWFzb25hYmxlIGJlbGllZnMgdGhlIHRydWUgbWVhc3VyZSBjb250aW51ZWQgbGluZWFybHkgYmV0d2VlbiB0aGUgb2JzZXJ2ZWQgcG9pbnRzLgoKYGBge3Isd2FybmluZz1GQUxTRSxtZXNzYWdlPUZBTFNFLGVycm9yPUZBTFNFfQoKI3dlIG5lZWQgdG8gcGFyYWxsZWxpemUgdGhpcyBjb2RlIGFuZCBzZWUgd2hhdCdzIGxvdWRseSB0aHJvd2luZwojRXJyb3IgaW4gY2hvbC5kZWZhdWx0KEoxMikgOiAKIyAgdGhlIGxlYWRpbmcgbWlub3Igb2Ygb3JkZXIgMSBpcyBub3QgcG9zaXRpdmUgZGVmaW5pdGUKCmRhdGFzZXRfcGxhY2VzIDwtIGxoc19sb25nX2NsZWFuICU+JSBkcGx5cjo6c2VsZWN0KGRhdGFzZXRfZ2lkX2dlb25hbWVpZF93aWtpZGF0YV9pZCkgJT4lIGRpc3RpbmN0KCkgJT4lIHB1bGwoZGF0YXNldF9naWRfZ2VvbmFtZWlkX3dpa2lkYXRhX2lkKQpsaWJyYXJ5KHBhcnR5KQp0ZW1wX2xpc3QxIDwtIGxpc3QoKQpvcHRpb25zKGVycm9yID0gZXhwcmVzc2lvbihOVUxMKSkKc2luayhOVUxMKQp6eiA8LSBmaWxlKCJtZXNzYWdlcy50eHQiLCBvcGVuID0gInd0IikKc2luayh6eikKc3VwcHJlc3NNZXNzYWdlcygKZm9yKHEgaW4gZGF0YXNldF9wbGFjZXMgICl7CiAgICAgICN0cnkoewogICAgICAgIHRlbXAgPC0gTlVMTAogICAgICAgIHRlbXAgPC0gbGhzX2xvbmdfY2xlYW4gJT4lCiAgICAgICAgICAgICAgICBmaWx0ZXIoZGF0YXNldF9naWRfZ2VvbmFtZWlkX3dpa2lkYXRhX2lkICVpbiUgcSkgJT4lCiAgICAgICAgICAgICAgICBhcnJhbmdlKGRhdGVfYXNkYXRlKSAlPiUKCiAgICAgICAgICAgICAgICBtdXRhdGUoY29uZmlybWVkX2xvZz1sb2coY29uZmlybWVkKSkgJT4lCiAgICAgICAgICAgICAgICBtdXRhdGUoZGVhdGhzX2xvZz1sb2coZGVhdGhzKSkgJT4lCiAgICAgICAgICAgICAgICBtdXRhdGUodGVzdGVkX3Blb3BsZV9sb2c9bG9nKHRlc3RlZF9wZW9wbGUpKSAlPiUKICAgICAgICAgICAgICAgIG11dGF0ZSh0ZXN0ZWRfc2FtcGxlc19sb2c9bG9nKHRlc3RlZF9zYW1wbGVzKSkgCiAgICAgICAgICAKICAgICAgICBpZihucm93KHRlbXApPT0wKXtuZXh0KCl9CiAgICAgICAgCiAgICAgICAgdGVtcCA8LSB0ZW1wICU+JSBleHBhbmQoZGF0YXNldCwgZ2lkX2dlb25hbWVpZF93aWtpZGF0YV9pZCwgZ2lkLCBnZW9uYW1laWQsd2lraWRhdGFfaWQsIGRhdGVfYXNkYXRlPW1pbihkYXRlX2FzZGF0ZSk6bWF4KGRhdGVfYXNkYXRlKSAlPiUgYXNfZGF0ZSgpICkgJT4lIAogICAgICAgICAgICAgICAgIGZ1bGxfam9pbih0ZW1wKSAlPiUgCiAgICAgICAgICAgICAgICAgbXV0YXRlKGRhdGVfYXNudW1lcmljPSBhcy5udW1lcmljKGRhdGVfYXNkYXRlKSApICU+JSAKICAgICAgICAgICAgICAgICBhcnJhbmdlKGRhdGVfYXNudW1lcmljKSAlPiUKICAgICAgICAgICAgICAgICBtdXRhdGUoY29uZmlybWVkX25vbm1pc3NpbmdfY291bnQgICAgID0gKCFpcy5uYShjb25maXJtZWQpKSAlPiUgY3Vtc3VtKCkgKSAlPiUKICAgICAgICAgICAgICAgICBtdXRhdGUoZGVhdGhzX25vbm1pc3NpbmdfY291bnQgICAgID0gKCFpcy5uYShkZWF0aHMpKSAlPiUgY3Vtc3VtKCkgKSAlPiUKICAgICAgICAgICAgICAgICBtdXRhdGUodGVzdGVkX3Blb3BsZV9ub25taXNzaW5nX2NvdW50ICAgICA9ICghaXMubmEodGVzdGVkX3Blb3BsZSkpICU+JSBjdW1zdW0oKSApICU+JQogICAgICAgICAgICAgICAgIG11dGF0ZSh0ZXN0ZWRfc2FtcGxlc19ub25taXNzaW5nX2NvdW50ICAgICA9ICghaXMubmEodGVzdGVkX3NhbXBsZXMpKSAlPiUgY3Vtc3VtKCkgKSAlPiUKICAgICAgICAKICAgICAgICAgICAgICAgICBhcnJhbmdlKC1kYXRlX2FzbnVtZXJpYykgJT4lCiAgICAgICAgICAgICAgICAgbXV0YXRlKGNvbmZpcm1lZF9ub25taXNzaW5nX2NvdW50X3JldmVyc2VkICAgICA9ICghaXMubmEoY29uZmlybWVkKSkgJT4lIGN1bXN1bSgpICkgJT4lCiAgICAgICAgICAgICAgICAgbXV0YXRlKGRlYXRoc19ub25taXNzaW5nX2NvdW50X3JldmVyc2VkICAgICA9ICghaXMubmEoZGVhdGhzKSkgJT4lIGN1bXN1bSgpICkgJT4lCiAgICAgICAgICAgICAgICAgbXV0YXRlKHRlc3RlZF9wZW9wbGVfbm9ubWlzc2luZ19jb3VudF9yZXZlcnNlZCAgICAgPSAoIWlzLm5hKHRlc3RlZF9wZW9wbGUpKSAlPiUgY3Vtc3VtKCkgKSAlPiUKICAgICAgICAgICAgICAgICBtdXRhdGUodGVzdGVkX3NhbXBsZXNfbm9ubWlzc2luZ19jb3VudF9yZXZlcnNlZCAgICAgPSAoIWlzLm5hKHRlc3RlZF9zYW1wbGVzKSkgJT4lIGN1bXN1bSgpICkgJT4lIAogICAgICAgICAgICAgICAgIGFycmFuZ2UoZGF0ZV9hc2RhdGUpIAoKICAgICAgICB0cnlDYXRjaCh7ICAKICAgICAgICAgIGlmKHN1bSghaXMubmEodGVtcCRjb25maXJtZWRfbG9nKSk+PTMpeyAjbmVlZCBhdCBsZWFzdCAzIHBvaW50cwogICAgICAgICAgICB0cmVlX2NvbmZpcm1lZCA8LSBwYXJ0eTo6bW9iKGNvbmZpcm1lZF9sb2cgfiAxICsgZGF0ZV9hc251bWVyaWMgICAgfCBkYXRlX2FzbnVtZXJpYyAsIGNvbnRyb2wgPSBtb2JfY29udHJvbChtaW5zcGxpdCA9IDMsIGFscGhhPS4yKSwgZGF0YSA9IHRlbXAsICBtb2RlbCA9IGxpbmVhck1vZGVsKSAgIyArIEkoZGF0ZV9hc251bWVyaWNeMikgIAogICAgICAgICAgICB0ZW1wJGNvbmZpcm1lZF9sb2dfeV9oYXQgPC0gcHJlZGljdCggdHJlZV9jb25maXJtZWQsIG5ld2RhdGE9dGVtcCAsIHR5cGUgPSBjKCJyZXNwb25zZSIpICkKICAgICAgICAgICAgdGVtcCRjb25maXJtZWRfbG9nX2dyb3VwX251bWJlciA8LSAgcHJlZGljdCggdHJlZV9jb25maXJtZWQsIG5ld2RhdGE9dGVtcCAsIHR5cGUgPSBjKCJub2RlIikpCiAgICAgICAgICAgIHRlbXAgPC0gdGVtcCAlPiUgCiAgICAgICAgICAgICAgICAgICAgbXV0YXRlKGNvbmZpcm1lZF9sb2dfeV9oYXQgICAgICAgPWlmZWxzZShjb25maXJtZWRfbm9ubWlzc2luZ19jb3VudD4wICYgY29uZmlybWVkX25vbm1pc3NpbmdfY291bnRfcmV2ZXJzZWQ+MCxjb25maXJtZWRfbG9nX3lfaGF0LE5BKSkgJT4lICNvbmx5IGludGVycG9sYXRlIHdpdGhpbiB0aGUgb2JzZXJ2ZWQgZGF0YSwgbmV2ZXIgYmVmb3JlIG9yIGFmdGVyCiAgICAgICAgICAgICAgICAgICAgbXV0YXRlKGNvbmZpcm1lZF9sb2dfZ3JvdXBfbnVtYmVyPWlmZWxzZShjb25maXJtZWRfbm9ubWlzc2luZ19jb3VudD4wICYgY29uZmlybWVkX25vbm1pc3NpbmdfY291bnRfcmV2ZXJzZWQ+MCxjb25maXJtZWRfbG9nX2dyb3VwX251bWJlcixOQSkpICU+JSAjb25seSBpbnRlcnBvbGF0ZSB3aXRoaW4gdGhlIG9ic2VydmVkIGRhdGEsIG5ldmVyIGJlZm9yZSBvciBhZnRlcgoKICAgICAgICAgICAgICAgICAgICBncm91cF9ieShjb25maXJtZWRfbG9nX2dyb3VwX251bWJlcikgJT4lCiAgICAgICAgICAgICAgICAgICAgYXJyYW5nZShkYXRlX2FzbnVtZXJpYykgJT4lCiAgICAgICAgICAgICAgICAgICAgbXV0YXRlKGNvbmZpcm1lZF9sb2dfeV9oYXRfc2xvcGU9dHNpYmJsZTo6ZGlmZmVyZW5jZShjb25maXJtZWRfbG9nX3lfaGF0KSkgJT4lIAogICAgICAgICAgICAgICAgICAgIGZpbGwoY29uZmlybWVkX2xvZ195X2hhdF9zbG9wZSwgLmRpcmVjdGlvbj0idXAiKSAlPiUgCiAgICAgICAgICAgICAgICAgICAgdW5ncm91cCgpICU+JQogICAgICAgICAgICAgICAgICAgIG11dGF0ZShjb25maXJtZWRfbG9nX3lfaGF0X3BlcmNlbnRfY2hhbmdlID0gcm91bmQoKGV4cChjb25maXJtZWRfbG9nX3lfaGF0X3Nsb3BlKS0xKSoxMDAsMikpICAlPiUKICAgICAgICAgICAgICAgICAgICBtdXRhdGUoY29uZmlybWVkX2xvZ195X2hhdD1pZmVsc2UoY29uZmlybWVkX2xvZ195X2hhdDwwLE5BLCBjb25maXJtZWRfbG9nX3lfaGF0KSkKICAgICAgICAgIH0KICAgICAgICB9LCBlcnJvciA9IGZ1bmN0aW9uKGUpIHt9LCBzaWxlbnQ9VFJVRSkKICAgICAgICAKICAgICAgICB0cnlDYXRjaCh7ICAKICAgICAgICAgIGlmKHN1bSghaXMubmEodGVtcCRkZWF0aHNfbG9nKSk+PTMpeyAjbmVlZCBhdCBsZWFzdCAzIHBvaW50cwogICAgICAgICAgICB0cmVlX2RlYXRocyA8LSBwYXJ0eTo6bW9iKGRlYXRoc19sb2cgfiAxICsgZGF0ZV9hc251bWVyaWMgICAgfCBkYXRlX2FzbnVtZXJpYyAsIGNvbnRyb2wgPSBtb2JfY29udHJvbChtaW5zcGxpdCA9IDMsIGFscGhhPS4yKSwgZGF0YSA9IHRlbXAsICBtb2RlbCA9IGxpbmVhck1vZGVsKSAgIyArIEkoZGF0ZV9hc251bWVyaWNeMikgICAgCiAgICAgICAgICAgIHRlbXAkZGVhdGhzX2xvZ195X2hhdCA8LSBwcmVkaWN0KCB0cmVlX2RlYXRocywgbmV3ZGF0YT10ZW1wICwgdHlwZSA9IGMoInJlc3BvbnNlIikgKQogICAgICAgICAgICB0ZW1wJGRlYXRoc19sb2dfZ3JvdXBfbnVtYmVyIDwtICBwcmVkaWN0KCB0cmVlX2RlYXRocywgbmV3ZGF0YT10ZW1wICwgdHlwZSA9IGMoIm5vZGUiKSkKICAgICAgICAgICAgdGVtcCA8LSB0ZW1wICU+JSAKICAgICAgICAgICAgICAgICAgICBtdXRhdGUoZGVhdGhzX2xvZ195X2hhdD1pZmVsc2UoZGVhdGhzX25vbm1pc3NpbmdfY291bnQ+MCAmIGRlYXRoc19ub25taXNzaW5nX2NvdW50X3JldmVyc2VkPjAsZGVhdGhzX2xvZ195X2hhdCxOQSkpICU+JSAjb25seSBpbnRlcnBvbGF0ZSB3aXRoaW4gdGhlIG9ic2VydmVkIGRhdGEsIG5ldmVyIGJlZm9yZQogICAgICAgICAgICAgICAgICAgIG11dGF0ZShkZWF0aHNfbG9nX2dyb3VwX251bWJlcj1pZmVsc2UoZGVhdGhzX25vbm1pc3NpbmdfY291bnQ+MCAmIGRlYXRoc19ub25taXNzaW5nX2NvdW50X3JldmVyc2VkPjAsZGVhdGhzX2xvZ19ncm91cF9udW1iZXIsTkEpKSAlPiUgI29ubHkgaW50ZXJwb2xhdGUgd2l0aGluIHRoZSBvYnNlcnZlZCBkYXRhLCBuZXZlciBiZWZvcmUKCiAgICAgICAgICAgICAgICAgICAgZ3JvdXBfYnkoZGVhdGhzX2xvZ19ncm91cF9udW1iZXIpICU+JSAKICAgICAgICAgICAgICAgICAgICBhcnJhbmdlKGRhdGVfYXNudW1lcmljKSAlPiUgCiAgICAgICAgICAgICAgICAgICAgbXV0YXRlKGRlYXRoc19sb2dfeV9oYXRfc2xvcGU9dHNpYmJsZTo6ZGlmZmVyZW5jZShkZWF0aHNfbG9nX3lfaGF0KSkgJT4lCiAgICAgICAgICAgICAgICAgICAgZmlsbChkZWF0aHNfbG9nX3lfaGF0X3Nsb3BlLCAuZGlyZWN0aW9uPSJ1cCIpICU+JQogICAgICAgICAgICAgICAgICAgIHVuZ3JvdXAoKSAlPiUKICAgICAgICAgICAgICAgICAgICBtdXRhdGUoZGVhdGhzX2xvZ195X2hhdF9wZXJjZW50X2NoYW5nZSA9IHJvdW5kKChleHAoZGVhdGhzX2xvZ195X2hhdF9zbG9wZSktMSkqMTAwLDIpKSAlPiUKICAgICAgICAgICAgICAgICAgICBtdXRhdGUoZGVhdGhzX2xvZ195X2hhdD1pZmVsc2UoZGVhdGhzX2xvZ195X2hhdDwwLE5BLCBkZWF0aHNfbG9nX3lfaGF0KSkgI3JlamVjdCBhbnkgd2hlcmUgdGhlIHByZWRpY3Rpb24gaXMgbGVzcyB0aGFuIDEgZnVsbCBjYXNlCiAgICAgICAgICB9CiAgICAgICAgfSwgZXJyb3IgPSBmdW5jdGlvbihlKSB7fSwgc2lsZW50PVRSVUUpCiAgICAgICAgCiAgICAgICAgdHJ5Q2F0Y2goeyAgCiAgICAgICAgICBpZihzdW0oIWlzLm5hKHRlbXAkdGVzdGVkX3Blb3BsZV9sb2cpKT49Myl7ICNuZWVkIGF0IGxlYXN0IDMgcG9pbnRzCiAgICAgICAgICAgIHRyZWVfdGVzdGVkX3Blb3BsZSA8LSBwYXJ0eTo6bW9iKHRlc3RlZF9wZW9wbGVfbG9nIH4gMSArIGRhdGVfYXNudW1lcmljICAgIHwgZGF0ZV9hc251bWVyaWMgLCBjb250cm9sID0gbW9iX2NvbnRyb2wobWluc3BsaXQgPSAzLCBhbHBoYT0uMiksIGRhdGEgPSB0ZW1wLCAgbW9kZWwgPSBsaW5lYXJNb2RlbCkgICMgKyBJKGRhdGVfYXNudW1lcmljXjIpICAgCiAgICAgICAgICAgIHRlbXAkdGVzdGVkX3Blb3BsZV9sb2dfeV9oYXQgPC0gcHJlZGljdCggdHJlZV90ZXN0ZWRfcGVvcGxlLCBuZXdkYXRhPXRlbXAgLCB0eXBlID0gYygicmVzcG9uc2UiKSApCiAgICAgICAgICAgIHRlbXAkdGVzdGVkX3Blb3BsZV9sb2dfZ3JvdXBfbnVtYmVyIDwtICBwcmVkaWN0KCB0cmVlX3Rlc3RlZF9wZW9wbGUsIG5ld2RhdGE9dGVtcCAsIHR5cGUgPSBjKCJub2RlIikpCiAgICAgICAgICAgIHRlbXAgPC0gdGVtcCAlPiUgCiAgICAgICAgICAgICAgICAgICAgICAgbXV0YXRlKHRlc3RlZF9wZW9wbGVfbG9nX3lfaGF0PWlmZWxzZSh0ZXN0ZWRfcGVvcGxlX25vbm1pc3NpbmdfY291bnQ+MCAmIHRlc3RlZF9wZW9wbGVfbm9ubWlzc2luZ19jb3VudF9yZXZlcnNlZD4wLHRlc3RlZF9wZW9wbGVfbG9nX3lfaGF0LE5BKSkgJT4lICNvbmx5IGludGVycG9sYXRlIHdpdGhpbiB0aGUgb2JzZXJ2ZWQgZGF0YSwgbmV2ZXIgYmVmb3JlCiAgICAgICAgICAgICAgICAgICAgICAgbXV0YXRlKHRlc3RlZF9wZW9wbGVfbG9nX2dyb3VwX251bWJlcj1pZmVsc2UodGVzdGVkX3Blb3BsZV9ub25taXNzaW5nX2NvdW50PjAgJiB0ZXN0ZWRfcGVvcGxlX25vbm1pc3NpbmdfY291bnRfcmV2ZXJzZWQ+MCx0ZXN0ZWRfcGVvcGxlX2xvZ19ncm91cF9udW1iZXIsTkEpKSAlPiUgI29ubHkgaW50ZXJwb2xhdGUgd2l0aGluIHRoZSBvYnNlcnZlZCBkYXRhLCBuZXZlciBiZWZvcmUKICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICBncm91cF9ieSh0ZXN0ZWRfcGVvcGxlX2xvZ19ncm91cF9udW1iZXIpICU+JSAKICAgICAgICAgICAgICAgICAgICAgICBhcnJhbmdlKGRhdGVfYXNudW1lcmljKSAlPiUKICAgICAgICAgICAgICAgICAgICAgICBtdXRhdGUodGVzdGVkX3Blb3BsZV9sb2dfeV9oYXRfc2xvcGU9dHNpYmJsZTo6ZGlmZmVyZW5jZSh0ZXN0ZWRfcGVvcGxlX2xvZ195X2hhdCkpICU+JSAKICAgICAgICAgICAgICAgICAgICAgICBmaWxsKHRlc3RlZF9wZW9wbGVfbG9nX3lfaGF0X3Nsb3BlLCAuZGlyZWN0aW9uPSJ1cCIpICU+JSB1bmdyb3VwKCkgJT4lCiAgICAgICAgICAgICAgICAgICAgICAgbXV0YXRlKHRlc3RlZF9wZW9wbGVfbG9nX3lfaGF0X3BlcmNlbnRfY2hhbmdlID0gcm91bmQoKGV4cCh0ZXN0ZWRfcGVvcGxlX2xvZ195X2hhdF9zbG9wZSktMSkqMTAwLDIpKSAlPiUKICAgICAgICAgICAgICAgICAgICAgICBtdXRhdGUodGVzdGVkX3Blb3BsZV9sb2dfeV9oYXQ9aWZlbHNlKHRlc3RlZF9wZW9wbGVfbG9nX3lfaGF0PDAsTkEsIHRlc3RlZF9wZW9wbGVfbG9nX3lfaGF0KSkgI3JlamVjdCBhbnkgd2hlcmUgdGhlIHByZWRpY3Rpb24gaXMgbGVzcyB0aGFuIDEgZnVsbCBjYXNlCiAgICAgICAgICB9CiAgICAgICAgfSwgZXJyb3IgPSBmdW5jdGlvbihlKSB7fSwgc2lsZW50PVRSVUUpCiAgICAgICAgCiAgICAgICAgdGVtcF9saXN0MVtbcSBdXSA8LSB0ZW1wCiAgCiAgICAgICN9KQp9CikKc2luayhOVUxMKQpsaHNfbG9uZ19jbGVhbl9pbXB1dGVkMSA8LSBiaW5kX3Jvd3ModGVtcF9saXN0MSkKZGltKGxoc19sb25nX2NsZWFuX2ltcHV0ZWQxKSAjNTAwLDc4NiAjYmlnZ2VyIGJlY2F1c2Ugd2UncmUgaW50ZXJwb2xhdGluZyBub3cKCiNydDEgPC0gcnBhcnQoZm9ybXVsYSA9IGNvbmZpcm1lZF9sb2dfeV9oYXRfcGVyY2VudF9jaGFuZ2UgfiBkYXRlX2FzbnVtZXJpYywgZGF0YT10ZXN0KQojaW50ZXJwb2xhdGVkID0gZGF0YS5mcmFtZShkYXRlX2FzbnVtZXJpYz1taW4odGVzdCRkYXRlX2FzbnVtZXJpYyk6bWF4KHRlc3QkZGF0ZV9hc251bWVyaWMpICkKI2ludGVycG9sYXRlZCRjb25maXJtZWRfbG9nX3lfaGF0X3BlcmNlbnRfY2hhbmdlX3lfaGF0IDwtICBwcmVkaWN0KHJ0MSwgbmV3ZGF0YT1pbnRlcnBvbGF0ZWQpCiNpbnRlcnBvbGF0ZWQkZGF0ZV9hc2RhdGUgPC0gYXMuRGF0ZShpbnRlcnBvbGF0ZWQkZGF0ZV9hc251bWVyaWMpCgpwbGFjZXMgPC0gbGhzX2xvbmdfY2xlYW4gJT4lIGRwbHlyOjpzZWxlY3QoZ2lkX2dlb25hbWVpZF93aWtpZGF0YV9pZCkgJT4lIGRpc3RpbmN0KCkgJT4lIHB1bGwoZ2lkX2dlb25hbWVpZF93aWtpZGF0YV9pZCkKCmxpYnJhcnkocnBhcnQpCm1pbnNwbGl0PTYKbWluYnVja2V0PTMKdGVtcF9saXN0MiA8LSBsaXN0KCkKZm9yKHEgaW4gcGxhY2VzICl7CiAgcHJpbnQocSkKICB0ZW1wIDwtIGxoc19sb25nX2NsZWFuX2ltcHV0ZWQxICU+JSAKICAgICAgICAgICAgICAgICBmaWx0ZXIoZ2lkX2dlb25hbWVpZF93aWtpZGF0YV9pZCAlaW4lIHEpICU+JSAKICAgICAgICAgICAgICAgICBhcnJhbmdlKGRhdGVfYXNudW1lcmljKSAKICAgIAogICAgICAgICAgCiAgdHJ5Q2F0Y2goeyAgCiAgICBydDEgPC0gcnBhcnQ6OnJwYXJ0KGZvcm11bGEgPSBjb25maXJtZWRfbG9nX3lfaGF0X3BlcmNlbnRfY2hhbmdlIH4gZGF0ZV9hc251bWVyaWMsCiAgICAgICAgICAgICAgICAgICAgICAgIGRhdGE9dGVtcCAlPiUgZmlsdGVyKCFpcy5uYShjb25maXJtZWRfbG9nKSksICN0byBrZWVwIGZyb20gZml0dGluZyB0byBpbnRlcnBvbGF0ZSBzbG9wZXMgdGhhdCBhcmUgb3V0IG9mIGRvbWFpbiBhbmQgdXN1YWxseSB3cm9uZywgcmVxdWlyZSBjb25maXJtZWQgdG8gbm90IGJlIG1pc3Npbmcgb3IgbmEKICAgICAgICAgICAgICAgICAgICAgICAgY29udHJvbCA9IHJwYXJ0LmNvbnRyb2wobWluc3BsaXQgPSBtaW5zcGxpdCwgbWluYnVja2V0PW1pbmJ1Y2tldCkpCiAgICB0ZW1wJGNvbmZpcm1lZF9sb2dfeV9oYXRfcGVyY2VudF9jaGFuZ2VfeV9oYXQgPC0gIHByZWRpY3QocnQxLCBuZXdkYXRhPXRlbXApICN0aGlzIHByZWRpY3Rpb24gaGVscGZ1bGx5IHRyaWVzIHRvIGltcHV0ZSBiYWNrd2FyZHMgZXZlbiBiZWZvcmUgdGhlcmUgYXJlIGFueSBkYXkgaW4gYW55IHNlcmllcwogICAgI1dlIG5lZWQgdG8gbnVrZSBpdCBpZiBubyBkYXRhIGV4aXN0CiAgICB0ZW1wIDwtIHRlbXAgJT4lCiAgICAgICAgICAgIGdyb3VwX2J5KGRhdGVfYXNkYXRlKSAlPiUKICAgICAgICAgICAgbXV0YXRlKCBjb25maXJtZWRfbm9ubWlzc2luZ19jb3VudF9kYXRhc2V0cz1zdW0oY29uZmlybWVkX25vbm1pc3NpbmdfY291bnQ+MCxuYS5ybT1UKSApICU+JQogICAgICAgICAgICBtdXRhdGUoIGNvbmZpcm1lZF9ub25taXNzaW5nX2NvdW50X2RhdGFzZXRzX3JldmVyc2VkPXN1bShjb25maXJtZWRfbm9ubWlzc2luZ19jb3VudF9yZXZlcnNlZD4wLG5hLnJtPVQpICkgJT4lCiAgICAgICAgICAgIG11dGF0ZShjb25maXJtZWRfbG9nX3lfaGF0X3BlcmNlbnRfY2hhbmdlX3lfaGF0PWlmZWxzZShjb25maXJtZWRfbm9ubWlzc2luZ19jb3VudF9kYXRhc2V0cz4wICYgY29uZmlybWVkX25vbm1pc3NpbmdfY291bnRfZGF0YXNldHNfcmV2ZXJzZWQ+MCxjb25maXJtZWRfbG9nX3lfaGF0X3BlcmNlbnRfY2hhbmdlX3lfaGF0LE5BKSkgICU+JQogICAgICB1bmdyb3VwKCkKICAgIAogIH0sIGVycm9yID0gZnVuY3Rpb24oZSkge30pCiAgCiAgdHJ5Q2F0Y2goeyAgCiAgICBydDIgPC0gcnBhcnQ6OnJwYXJ0KGZvcm11bGEgPSBkZWF0aHNfbG9nX3lfaGF0X3BlcmNlbnRfY2hhbmdlIH4gZGF0ZV9hc251bWVyaWMsCiAgICAgICAgICAgICAgICAgICAgICAgIGRhdGE9dGVtcCAlPiUgZmlsdGVyKCFpcy5uYShkZWF0aHNfbG9nKSksCiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnRyb2wgPSBycGFydC5jb250cm9sKG1pbnNwbGl0ID0gbWluc3BsaXQsIG1pbmJ1Y2tldD1taW5idWNrZXQpKQogICAgdGVtcCRkZWF0aHNfbG9nX3lfaGF0X3BlcmNlbnRfY2hhbmdlX3lfaGF0IDwtICBwcmVkaWN0KHJ0MiwgbmV3ZGF0YT10ZW1wKQogICAgdGVtcCA8LSB0ZW1wICU+JQogICAgICAgIGdyb3VwX2J5KGRhdGVfYXNkYXRlKSAlPiUKICAgICAgICBtdXRhdGUoIGRlYXRoc19ub25taXNzaW5nX2NvdW50X2RhdGFzZXRzPXN1bShkZWF0aHNfbm9ubWlzc2luZ19jb3VudD4wLG5hLnJtPVQpICkgJT4lCiAgICAgICAgbXV0YXRlKCBkZWF0aHNfbm9ubWlzc2luZ19jb3VudF9kYXRhc2V0c19yZXZlcnNlZD1zdW0oZGVhdGhzX25vbm1pc3NpbmdfY291bnRfcmV2ZXJzZWQ+MCxuYS5ybT1UKSApICU+JQogICAgICAgIG11dGF0ZShkZWF0aHNfbG9nX3lfaGF0X3BlcmNlbnRfY2hhbmdlX3lfaGF0PWlmZWxzZShkZWF0aHNfbm9ubWlzc2luZ19jb3VudF9kYXRhc2V0cz4wICYgZGVhdGhzX25vbm1pc3NpbmdfY291bnRfZGF0YXNldHNfcmV2ZXJzZWQ+MCxkZWF0aHNfbG9nX3lfaGF0X3BlcmNlbnRfY2hhbmdlX3lfaGF0LE5BKSkgJT4lCiAgICAgIHVuZ3JvdXAoKQogICAgICAgIAogIH0sIGVycm9yID0gZnVuY3Rpb24oZSkge30pCgogIHRyeUNhdGNoKHsgIAogICAgcnQzIDwtIHJwYXJ0OjpycGFydChmb3JtdWxhID0gdGVzdGVkX3Blb3BsZV9sb2dfeV9oYXRfcGVyY2VudF9jaGFuZ2UgfiBkYXRlX2FzbnVtZXJpYywKICAgICAgICAgICAgICAgICAgICBkYXRhPXRlbXAgJT4lIGZpbHRlcighaXMubmEodGVzdGVkX3Blb3BsZV9sb2cpKSwKICAgICAgICAgICAgICAgICAgICBjb250cm9sID0gcnBhcnQuY29udHJvbChtaW5zcGxpdCA9IG1pbnNwbGl0LCBtaW5idWNrZXQ9bWluYnVja2V0KSkKICAgIHRlbXAkdGVzdGVkX3Blb3BsZV9sb2dfeV9oYXRfcGVyY2VudF9jaGFuZ2VfeV9oYXQgPC0gIHByZWRpY3QocnQzLCBuZXdkYXRhPXRlbXAsIGNvbnRyb2wgPSBycGFydC5jb250cm9sKG1pbnNwbGl0ID0gbWluc3BsaXQsIG1pbmJ1Y2tldD1taW5idWNrZXQpKQogICAgdGVtcCA8LSB0ZW1wICU+JQogICAgICAgIGdyb3VwX2J5KGRhdGVfYXNkYXRlKSAlPiUKICAgICAgICBtdXRhdGUoIHRlc3RlZF9wZW9wbGVfbm9ubWlzc2luZ19jb3VudF9kYXRhc2V0cz1zdW0odGVzdGVkX3Blb3BsZV9ub25taXNzaW5nX2NvdW50PjAsbmEucm09VCkgKSAlPiUKICAgICAgICBtdXRhdGUoIHRlc3RlZF9wZW9wbGVfbm9ubWlzc2luZ19jb3VudF9kYXRhc2V0c19yZXZlcnNlZD1zdW0odGVzdGVkX3Blb3BsZV9ub25taXNzaW5nX2NvdW50X3JldmVyc2VkPjAsbmEucm09VCkgKSAlPiUKICAgICAgCiAgICAgICAgbXV0YXRlKHRlc3RlZF9wZW9wbGVfbG9nX3lfaGF0X3BlcmNlbnRfY2hhbmdlX3lfaGF0PWlmZWxzZSh0ZXN0ZWRfcGVvcGxlX25vbm1pc3NpbmdfY291bnRfZGF0YXNldHM+MCAmIHRlc3RlZF9wZW9wbGVfbm9ubWlzc2luZ19jb3VudF9kYXRhc2V0c19yZXZlcnNlZD4wLHRlc3RlZF9wZW9wbGVfbG9nX3lfaGF0X3BlcmNlbnRfY2hhbmdlX3lfaGF0LE5BKSkgICU+JQogICAgICB1bmdyb3VwKCkKICB9LCBlcnJvciA9IGZ1bmN0aW9uKGUpIHt9KQogIAogIHRlbXBfbGlzdDJbW3EgXV0gPC0gdGVtcAp9Cmxoc19sb25nX2NsZWFuX2ltcHV0ZWQyIDwtIGJpbmRfcm93cyh0ZW1wX2xpc3QyKQoKbGhzX2xvbmdfY2xlYW5faW1wdXRlZCA8LSBsaHNfbG9uZ19jbGVhbl9pbXB1dGVkMgpkaW0obGhzX2xvbmdfY2xlYW5faW1wdXRlZCkgIzYyOSw0OTMgIzQxOTkxMCAjNDEzNDc1ICM0MDgsMzY5ICN3ZSBsb3NlIGFueXdpdGhvdXQgcSBjb2RlcyBoZXJlCnNhdmVSRFMobGhzX2xvbmdfY2xlYW5faW1wdXRlZCwgIi9tZWRpYS9za3luZXQyLzkwNTg4NGYwLTc1NDYtNDI3My05MDYxLTEyYTc5MDgzMGJlYi9yd2RfZ2l0aHViX3ByaXZhdGUvTkVTU2NvdmlkMTkvZGF0YV90ZW1wL2xoc19sb25nX2NsZWFuX2ltcHV0ZWQuUmRzIikKCmBgYAoKIyMjIEV4YW1wbGVzCgojIyMjIENoaW5hCgpgYGB7ciwgZmlnLndpZHRoPTE2LCBmaWcuaGVpZ2h0PTEyLHdhcm5pbmc9RkFMU0UsbWVzc2FnZT1GQUxTRSxlcnJvcj1GQUxTRSwgcmVzdWx0cz0naGlkZSd9CiNDaGluYQojIlExNDgiCgp0ZXN0IDwtIGxoc19sb25nX2NsZWFuX2ltcHV0ZWQgJT4lIAogICAgICAgIG11dGF0ZShncm91cD1wYXN0ZShkYXRhc2V0LHdpa2lkYXRhX2lkLGNvbmZpcm1lZF9sb2dfeV9oYXRfcGVyY2VudF9jaGFuZ2UpKSAlPiUgZmlsdGVyKHdpa2lkYXRhX2lkPT0iUTE0OCIpICU+JSAKICAgICAgICBtdXRhdGUoZ3JvdXA9cGFzdGUoZGF0YXNldCwgd2lraWRhdGFfaWQsY29uZmlybWVkX2xvZ19ncm91cF9udW1iZXIpKSAlPiUKICAgICAgICBhcnJhbmdlKGRhdGVfYXNkYXRlKSAjJT4lCiAgICAgICAgI211dGF0ZSggY29uZmlybWVkX2xvZ195X2hhdF9wZXJjZW50X2NoYW5nZSA9IGJyZWFrcG9pbnRzKGZvcm11bGE9Y29uZmlybWVkX2xvZ195X2hhdF9wZXJjZW50X2NoYW5nZSB+IDEsIGRhdGE9LiApICU+JSBmaXR0ZWQudmFsdWVzKCkgKQoKcF9pbnRlcnBvbGF0aW9uMCA8LSB0ZXN0ICU+JQogICAgICAgICAgICAgICAgICAgIGdncGxvdCgpICsgCiAgICAgICAgICAgICAgICAgICAgICAgZ2VvbV9wb2ludCggYWVzKHg9ZGF0ZV9hc2RhdGUsIHk9Y29uZmlybWVkX2xvZywgY29sb3I9ZGF0YXNldCksIGFscGhhPS4zKSArCiAgICAgICAgICAgICAgICAgICAgICAgZ2VvbV9saW5lKCBhZXMoeD1kYXRlX2FzZGF0ZSwgeT1jb25maXJtZWRfbG9nX3lfaGF0LCBjb2xvcj1kYXRhc2V0LCBncm91cD1ncm91cCkpICsgIwogICAgICAgICAgICAgICAgICAgICAgICNnZW9tX2xpbmUoZGF0YT10ZW1wX2RmMiwgYWVzKHg9ZGF0ZV9hc2RhdGUsIHk9eV9oYXRfbWVhbiksIGNvbG9yPSJibGFjayIsIGxpbmV0eXBlID0gImRhc2hlZCIpICsKICAgICAgICAgICAgICAgICAgICAgICB0aGVtZV9idygpICsKICAgICAgICAgICAgICAgICAgICAgICBnZ3RpdGxlKCJDaGluYSBRMTQ4IENvbmZpcm1lZCIpICsgZmFjZXRfd3JhcCh+ZGF0YXNldCAgICkKCmBgYAoKRGF0YSBvbiBDaGluYSBzaG93cyB2YXJpYXRpb24gYWNyb3NzIGRhdGFzZXRzIGZvciB3aGVuIHRoZXkgc3RhcnQgbWVhc3VyaW5nLiBPbmx5IHR3byBvYnNlcnZlIHRoZSB2ZXJ5IGJlZ2lubmluZyBvZiB0aGUgb3V0YnJlYWsuIEFsbCBvZiB0aGUgZGF0YXNldHMgc2hvdyBhIGRpc2NvbnRpbnVpdHkgd2hlcmUgcmVwb3J0aW5nIHN0YW5kYXJkcyBtdXN0IGhhdmUgY2hhbmdlZC4gT3VyIG1ldGhvZCBhdHRlbXB0cyB0byBicmlkZ2UgdGhhdCBnYXAgaW4gMyBvZiB0aGUgc2VyaWVzIGJ1dCBub3QgdHdvIG90aGVycy4KCmBgYHtyLCBmaWcud2lkdGg9OCwgZmlnLmhlaWdodD02LHdhcm5pbmc9RkFMU0UsbWVzc2FnZT1GQUxTRSxlcnJvcj1GQUxTRX0KcF9pbnRlcnBvbGF0aW9uMApgYGAKIyMjIyBJdGFseSAKCmBgYHtyLCBmaWcud2lkdGg9MTYsIGZpZy5oZWlnaHQ9MTIsd2FybmluZz1GQUxTRSxtZXNzYWdlPUZBTFNFLGVycm9yPUZBTFNFLCByZXN1bHRzPSdoaWRlJ30KI0l0YWx5CiMiUTM4IgoKdGVzdCA8LSBsaHNfbG9uZ19jbGVhbl9pbXB1dGVkICU+JSBtdXRhdGUoZ3JvdXA9cGFzdGUoZGF0YXNldCx3aWtpZGF0YV9pZCxjb25maXJtZWRfbG9nX3lfaGF0X3BlcmNlbnRfY2hhbmdlKSkgJT4lIGZpbHRlcih3aWtpZGF0YV9pZD09IlEzOCIpICU+JSAKICAgICAgICBtdXRhdGUoZ3JvdXA9cGFzdGUoZGF0YXNldCwgd2lraWRhdGFfaWQsY29uZmlybWVkX2xvZ19ncm91cF9udW1iZXIpKSAlPiUKICAgICAgICBhcnJhbmdlKGRhdGVfYXNkYXRlKSAjJT4lCiAgICAgICAgI211dGF0ZSggY29uZmlybWVkX2xvZ195X2hhdF9wZXJjZW50X2NoYW5nZSA9IGJyZWFrcG9pbnRzKGZvcm11bGE9Y29uZmlybWVkX2xvZ195X2hhdF9wZXJjZW50X2NoYW5nZSB+IDEsIGRhdGE9LiApICU+JSBmaXR0ZWQudmFsdWVzKCkgKQoKcF9pbnRlcnBvbGF0aW9uMSA8LSB0ZXN0ICU+JQogICAgICAgICAgICAgICAgICAgIGdncGxvdCgpICsgCiAgICAgICAgICAgICAgICAgICAgICAgZ2VvbV9wb2ludCggYWVzKHg9ZGF0ZV9hc2RhdGUsIHk9Y29uZmlybWVkX2xvZywgY29sb3I9ZGF0YXNldCksIGFscGhhPS4zKSArCiAgICAgICAgICAgICAgICAgICAgICAgZ2VvbV9saW5lKCBhZXMoeD1kYXRlX2FzZGF0ZSwgeT1jb25maXJtZWRfbG9nX3lfaGF0LCBjb2xvcj1kYXRhc2V0LCBncm91cD1ncm91cCkpICsgIwogICAgICAgICAgICAgICAgICAgICAgICNnZW9tX2xpbmUoZGF0YT10ZW1wX2RmMiwgYWVzKHg9ZGF0ZV9hc2RhdGUsIHk9eV9oYXRfbWVhbiksIGNvbG9yPSJibGFjayIsIGxpbmV0eXBlID0gImRhc2hlZCIpICsKICAgICAgICAgICAgICAgICAgICAgICB0aGVtZV9idygpICsKICAgICAgICAgICAgICAgICAgICAgICBnZ3RpdGxlKCJJdGFseSBRMzggQ29uZmlybWVkIikgKyBmYWNldF93cmFwKH5kYXRhc2V0ICAgKQoKYGBgCgpJdGFseSBsaWtld2lzZSBzaG93cyB2YXJpYXRpb24gaW4gdGhlIHN0YXJ0IG9mIHJlY29yZGluZyBhY3Jvc3MgZGF0YXNldHMuIFRoZXJlJ3MgYWxzbyB2YXJpYXRpb24gaW4gdGhlIGluaXRpYWwgc3BhcmNpdHkuIFdpa2lwZWRpYSBpcyBzdHJhbmdlbHkgbWlzc2luZyBkYXRhIGluIHRoZSBtaWRkbGUuIE91ciBtZXRob2QgbGluZWFybHkgaW50ZXJwb2xhdGVzIGludG8gdGhhdCBzcGFjZSBpbiBhIHdheSBpbiBhIHdheSB3ZSBwcm9iYWJseSBkb24ndCB3YW50LgoKYGBge3IsIGZpZy53aWR0aD04LCBmaWcuaGVpZ2h0PTYsd2FybmluZz1GQUxTRSxtZXNzYWdlPUZBTFNFLGVycm9yPUZBTFNFfQpwX2ludGVycG9sYXRpb24xCmBgYAoKIyMjIyBJdGFseSAKCmBgYHtyLCBmaWcud2lkdGg9MTYsIGZpZy5oZWlnaHQ9MTIsd2FybmluZz1GQUxTRSxtZXNzYWdlPUZBTFNFLGVycm9yPUZBTFNFLCByZXN1bHRzPSdoaWRlJ30KI1VTCiMiUTMwIgoKdGVzdCA8LSBsaHNfbG9uZ19jbGVhbl9pbXB1dGVkICU+JSBtdXRhdGUoZ3JvdXA9cGFzdGUoZGF0YXNldCx3aWtpZGF0YV9pZCxjb25maXJtZWRfbG9nX3lfaGF0X3BlcmNlbnRfY2hhbmdlKSkgJT4lIGZpbHRlcih3aWtpZGF0YV9pZD09IlEzMCIpICU+JSAKICAgICAgICBtdXRhdGUoZ3JvdXA9cGFzdGUoZGF0YXNldCwgd2lraWRhdGFfaWQsY29uZmlybWVkX2xvZ19ncm91cF9udW1iZXIpKSAlPiUKICAgICAgICBhcnJhbmdlKGRhdGVfYXNkYXRlKSAjJT4lCiAgICAgICAgI211dGF0ZSggY29uZmlybWVkX2xvZ195X2hhdF9wZXJjZW50X2NoYW5nZSA9IGJyZWFrcG9pbnRzKGZvcm11bGE9Y29uZmlybWVkX2xvZ195X2hhdF9wZXJjZW50X2NoYW5nZSB+IDEsIGRhdGE9LiApICU+JSBmaXR0ZWQudmFsdWVzKCkgKQoKcF9pbnRlcnBvbGF0aW9uMiA8LSB0ZXN0ICU+JQogICAgICAgICAgICAgICAgICAgIGdncGxvdCgpICsgCiAgICAgICAgICAgICAgICAgICAgICAgZ2VvbV9wb2ludCggYWVzKHg9ZGF0ZV9hc2RhdGUsIHk9Y29uZmlybWVkX2xvZywgY29sb3I9ZGF0YXNldCksIGFscGhhPS4zKSArCiAgICAgICAgICAgICAgICAgICAgICAgZ2VvbV9saW5lKCBhZXMoeD1kYXRlX2FzZGF0ZSwgeT1jb25maXJtZWRfbG9nX3lfaGF0LCBjb2xvcj1kYXRhc2V0LCBncm91cD1ncm91cCkpICsgIwogICAgICAgICAgICAgICAgICAgICAgICNnZW9tX2xpbmUoZGF0YT10ZW1wX2RmMiwgYWVzKHg9ZGF0ZV9hc2RhdGUsIHk9eV9oYXRfbWVhbiksIGNvbG9yPSJibGFjayIsIGxpbmV0eXBlID0gImRhc2hlZCIpICsKICAgICAgICAgICAgICAgICAgICAgICB0aGVtZV9idygpICsKICAgICAgICAgICAgICAgICAgICAgICBnZ3RpdGxlKCJVUyBRMzAgQ29uZmlybWVkIikgKyBmYWNldF93cmFwKH5kYXRhc2V0ICAgKQoKYGBgCgoKYGBge3IsIGZpZy53aWR0aD04LCBmaWcuaGVpZ2h0PTYsd2FybmluZz1GQUxTRSxtZXNzYWdlPUZBTFNFLGVycm9yPUZBTFNFfQpwX2ludGVycG9sYXRpb24yCmBgYAoKCiMjIyMgTmV3IFlvcmsgU3RhdGUKCmBgYHtyLCBmaWcud2lkdGg9MTYsIGZpZy5oZWlnaHQ9MTIsd2FybmluZz1GQUxTRSxtZXNzYWdlPUZBTFNFLGVycm9yPUZBTFNFLCByZXN1bHRzPSdoaWRlJ30KI1VTCiMiUTMwIgoKdGVzdCA8LSBsaHNfbG9uZ19jbGVhbl9pbXB1dGVkICU+JSBtdXRhdGUoZ3JvdXA9cGFzdGUoZGF0YXNldCx3aWtpZGF0YV9pZCxjb25maXJtZWRfbG9nX3lfaGF0X3BlcmNlbnRfY2hhbmdlKSkgJT4lIGZpbHRlcih3aWtpZGF0YV9pZD09IlExMzg0IikgJT4lIAogICAgICAgIG11dGF0ZShncm91cD1wYXN0ZShkYXRhc2V0LCB3aWtpZGF0YV9pZCxjb25maXJtZWRfbG9nX2dyb3VwX251bWJlcikpICU+JQogICAgICAgIGFycmFuZ2UoZGF0ZV9hc2RhdGUpICMlPiUKICAgICAgICAjbXV0YXRlKCBjb25maXJtZWRfbG9nX3lfaGF0X3BlcmNlbnRfY2hhbmdlID0gYnJlYWtwb2ludHMoZm9ybXVsYT1jb25maXJtZWRfbG9nX3lfaGF0X3BlcmNlbnRfY2hhbmdlIH4gMSwgZGF0YT0uICkgJT4lIGZpdHRlZC52YWx1ZXMoKSApCgpwX2ludGVycG9sYXRpb24zIDwtIHRlc3QgJT4lCiAgICAgICAgICAgICAgICAgICAgZ2dwbG90KCkgKyAKICAgICAgICAgICAgICAgICAgICAgICBnZW9tX3BvaW50KCBhZXMoeD1kYXRlX2FzZGF0ZSwgeT1jb25maXJtZWRfbG9nLCBjb2xvcj1kYXRhc2V0KSwgYWxwaGE9LjMpICsKICAgICAgICAgICAgICAgICAgICAgICBnZW9tX2xpbmUoIGFlcyh4PWRhdGVfYXNkYXRlLCB5PWNvbmZpcm1lZF9sb2dfeV9oYXQsIGNvbG9yPWRhdGFzZXQsIGdyb3VwPWdyb3VwKSkgKyAjCiAgICAgICAgICAgICAgICAgICAgICAgI2dlb21fbGluZShkYXRhPXRlbXBfZGYyLCBhZXMoeD1kYXRlX2FzZGF0ZSwgeT15X2hhdF9tZWFuKSwgY29sb3I9ImJsYWNrIiwgbGluZXR5cGUgPSAiZGFzaGVkIikgKwogICAgICAgICAgICAgICAgICAgICAgIHRoZW1lX2J3KCkgKwogICAgICAgICAgICAgICAgICAgICAgIGdndGl0bGUoIk5ldyBZb3JrIFN0YXRlIFExMzg0IENvbmZpcm1lZCIpICsgZmFjZXRfd3JhcCh+ZGF0YXNldCAgICkKCmBgYAoKCmBgYHtyLCBmaWcud2lkdGg9OCwgZmlnLmhlaWdodD02LHdhcm5pbmc9RkFMU0UsbWVzc2FnZT1GQUxTRSxlcnJvcj1GQUxTRX0KcF9pbnRlcnBvbGF0aW9uMwpgYGAKCiMjIyMgTmV3IFlvcmsgQ2l0eSAoYnkgY291bnR5KQoKbnl0IGhhcyBpdCBqdXN0IGJ5IGNpdHksIGl0IGRvZXNuJ3QgYnJlYWsgaXQgZG93biBieSB0aGUgYm9yb3VnaHMuIEJ1dCBiZWNhdXNlIGdhZG0gZG9lc24ndCBkbyBjaXRpZXMgd2UgZG9uJ3QgYXNzaWduIGl0IGEgcWNvZGUuCgp1c2FmYWN0cyBoYXMgaXQgYXMgTmV3IFlvcmsgQ291bnR5IHdoaWNoIGlzIE5ldyBZb3JrIENvdW50eSAoTWFuaGF0dGFuKQoKYGBge3IsIGZpZy53aWR0aD0xNiwgZmlnLmhlaWdodD0xMix3YXJuaW5nPUZBTFNFLG1lc3NhZ2U9RkFMU0UsZXJyb3I9RkFMU0UsIHJlc3VsdHM9J2hpZGUnfQojQnJvb2tseW4gKFExODQxOSkKdGVzdCA8LSBsaHNfbG9uZ19jbGVhbl9pbXB1dGVkICU+JSBtdXRhdGUoZ3JvdXA9cGFzdGUoZGF0YXNldCx3aWtpZGF0YV9pZCxjb25maXJtZWRfbG9nX3lfaGF0X3BlcmNlbnRfY2hhbmdlKSkgJT4lIGZpbHRlcih3aWtpZGF0YV9pZD09IlE4NTU5NzQiKSAlPiUgICNubyBoaXRzPwogICAgICAgIG11dGF0ZShncm91cD1wYXN0ZShkYXRhc2V0LCB3aWtpZGF0YV9pZCxjb25maXJtZWRfbG9nX2dyb3VwX251bWJlcikpICU+JQogICAgICAgIGFycmFuZ2UoZGF0ZV9hc2RhdGUpICMlPiUKICAgICAgICAjbXV0YXRlKCBjb25maXJtZWRfbG9nX3lfaGF0X3BlcmNlbnRfY2hhbmdlID0gYnJlYWtwb2ludHMoZm9ybXVsYT1jb25maXJtZWRfbG9nX3lfaGF0X3BlcmNlbnRfY2hhbmdlIH4gMSwgZGF0YT0uICkgJT4lIGZpdHRlZC52YWx1ZXMoKSApCgpwX2ludGVycG9sYXRpb240YSA8LSB0ZXN0ICU+JQogICAgICAgICAgICAgICAgICAgIGdncGxvdCgpICsgCiAgICAgICAgICAgICAgICAgICAgICAgZ2VvbV9wb2ludCggYWVzKHg9ZGF0ZV9hc2RhdGUsIHk9Y29uZmlybWVkX2xvZywgY29sb3I9ZGF0YXNldCksIGFscGhhPS4zKSArCiAgICAgICAgICAgICAgICAgICAgICAgZ2VvbV9saW5lKCBhZXMoeD1kYXRlX2FzZGF0ZSwgeT1jb25maXJtZWRfbG9nX3lfaGF0LCBjb2xvcj1kYXRhc2V0LCBncm91cD1ncm91cCkpICsgIwogICAgICAgICAgICAgICAgICAgICAgICNnZW9tX2xpbmUoZGF0YT10ZW1wX2RmMiwgYWVzKHg9ZGF0ZV9hc2RhdGUsIHk9eV9oYXRfbWVhbiksIGNvbG9yPSJibGFjayIsIGxpbmV0eXBlID0gImRhc2hlZCIpICsKICAgICAgICAgICAgICAgICAgICAgICB0aGVtZV9idygpICsKICAgICAgICAgICAgICAgICAgICAgICBnZ3RpdGxlKCJCcm9ueCBDb3VudHkgKFE4NTU5NzQpIikgKyBmYWNldF93cmFwKH5kYXRhc2V0ICAgKSArIGd1aWRlcyggY29sb3IgPSBGQUxTRSkKCiNRdWVlbnMgQ291bnR5LCBOZXcgWW9yayBRNTE0MjU1OQp0ZXN0IDwtIGxoc19sb25nX2NsZWFuX2ltcHV0ZWQgJT4lIG11dGF0ZShncm91cD1wYXN0ZShkYXRhc2V0LHdpa2lkYXRhX2lkLGNvbmZpcm1lZF9sb2dfeV9oYXRfcGVyY2VudF9jaGFuZ2UpKSAlPiUgZmlsdGVyKHdpa2lkYXRhX2lkPT0iUTUxNDI1NTkiKSAlPiUgICNubyBoaXRzPwogICAgICAgIG11dGF0ZShncm91cD1wYXN0ZShkYXRhc2V0LCB3aWtpZGF0YV9pZCxjb25maXJtZWRfbG9nX2dyb3VwX251bWJlcikpICU+JQogICAgICAgIGFycmFuZ2UoZGF0ZV9hc2RhdGUpICMlPiUKICAgICAgICAjbXV0YXRlKCBjb25maXJtZWRfbG9nX3lfaGF0X3BlcmNlbnRfY2hhbmdlID0gYnJlYWtwb2ludHMoZm9ybXVsYT1jb25maXJtZWRfbG9nX3lfaGF0X3BlcmNlbnRfY2hhbmdlIH4gMSwgZGF0YT0uICkgJT4lIGZpdHRlZC52YWx1ZXMoKSApCgpwX2ludGVycG9sYXRpb240YiA8LSB0ZXN0ICU+JQogICAgICAgICAgICAgICAgICAgIGdncGxvdCgpICsgCiAgICAgICAgICAgICAgICAgICAgICAgZ2VvbV9wb2ludCggYWVzKHg9ZGF0ZV9hc2RhdGUsIHk9Y29uZmlybWVkX2xvZywgY29sb3I9ZGF0YXNldCksIGFscGhhPS4zKSArCiAgICAgICAgICAgICAgICAgICAgICAgZ2VvbV9saW5lKCBhZXMoeD1kYXRlX2FzZGF0ZSwgeT1jb25maXJtZWRfbG9nX3lfaGF0LCBjb2xvcj1kYXRhc2V0LCBncm91cD1ncm91cCkpICsgIwogICAgICAgICAgICAgICAgICAgICAgICNnZW9tX2xpbmUoZGF0YT10ZW1wX2RmMiwgYWVzKHg9ZGF0ZV9hc2RhdGUsIHk9eV9oYXRfbWVhbiksIGNvbG9yPSJibGFjayIsIGxpbmV0eXBlID0gImRhc2hlZCIpICsKICAgICAgICAgICAgICAgICAgICAgICB0aGVtZV9idygpICsKICAgICAgICAgICAgICAgICAgICAgICBnZ3RpdGxlKCJRdWVlbnMgQ291bnR5LCBOZXcgWW9yayBRNTE0MjU1OSIpICsgZmFjZXRfd3JhcCh+ZGF0YXNldCAgICkgKyBndWlkZXMoIGNvbG9yID0gRkFMU0UpCgojQnJvb2tseW4gaXMgYXBhcmVudGx5IEtpbmdzIENvdW50eSBRMTE5ODA2OTIKdGVzdCA8LSBsaHNfbG9uZ19jbGVhbl9pbXB1dGVkICU+JSBtdXRhdGUoZ3JvdXA9cGFzdGUoZGF0YXNldCx3aWtpZGF0YV9pZCxjb25maXJtZWRfbG9nX3lfaGF0X3BlcmNlbnRfY2hhbmdlKSkgJT4lIGZpbHRlcih3aWtpZGF0YV9pZD09IlExMTk4MDY5MiIpICU+JSAgI25vIGhpdHM/CiAgICAgICAgbXV0YXRlKGdyb3VwPXBhc3RlKGRhdGFzZXQsIHdpa2lkYXRhX2lkLGNvbmZpcm1lZF9sb2dfZ3JvdXBfbnVtYmVyKSkgJT4lCiAgICAgICAgYXJyYW5nZShkYXRlX2FzZGF0ZSkgIyU+JQogICAgICAgICNtdXRhdGUoIGNvbmZpcm1lZF9sb2dfeV9oYXRfcGVyY2VudF9jaGFuZ2UgPSBicmVha3BvaW50cyhmb3JtdWxhPWNvbmZpcm1lZF9sb2dfeV9oYXRfcGVyY2VudF9jaGFuZ2UgfiAxLCBkYXRhPS4gKSAlPiUgZml0dGVkLnZhbHVlcygpICkKCnBfaW50ZXJwb2xhdGlvbjRjIDwtIHRlc3QgJT4lCiAgICAgICAgICAgICAgICAgICAgZ2dwbG90KCkgKyAKICAgICAgICAgICAgICAgICAgICAgICBnZW9tX3BvaW50KCBhZXMoeD1kYXRlX2FzZGF0ZSwgeT1jb25maXJtZWRfbG9nLCBjb2xvcj1kYXRhc2V0KSwgYWxwaGE9LjMpICsKICAgICAgICAgICAgICAgICAgICAgICBnZW9tX2xpbmUoIGFlcyh4PWRhdGVfYXNkYXRlLCB5PWNvbmZpcm1lZF9sb2dfeV9oYXQsIGNvbG9yPWRhdGFzZXQsIGdyb3VwPWdyb3VwKSkgKyAjCiAgICAgICAgICAgICAgICAgICAgICAgI2dlb21fbGluZShkYXRhPXRlbXBfZGYyLCBhZXMoeD1kYXRlX2FzZGF0ZSwgeT15X2hhdF9tZWFuKSwgY29sb3I9ImJsYWNrIiwgbGluZXR5cGUgPSAiZGFzaGVkIikgKwogICAgICAgICAgICAgICAgICAgICAgIHRoZW1lX2J3KCkgKwogICAgICAgICAgICAgICAgICAgICAgIGdndGl0bGUoIkJyb29rbHluIGlzIEtpbmdzIENvdW50eSBRMTE5ODA2OTIiKSArIGZhY2V0X3dyYXAofmRhdGFzZXQgICApICsgZ3VpZGVzKCBjb2xvciA9IEZBTFNFKQoKIyBNYW5oYXR0YW4gaXMgTmV3IFlvcmsgQ291bnR5IFE1MDA0MTYKdGVzdCA8LSBsaHNfbG9uZ19jbGVhbl9pbXB1dGVkICU+JSBtdXRhdGUoZ3JvdXA9cGFzdGUoZGF0YXNldCx3aWtpZGF0YV9pZCxjb25maXJtZWRfbG9nX3lfaGF0X3BlcmNlbnRfY2hhbmdlKSkgJT4lIGZpbHRlcih3aWtpZGF0YV9pZD09IlE1MDA0MTYiKSAlPiUgICNubyBoaXRzPwogICAgICAgIG11dGF0ZShncm91cD1wYXN0ZShkYXRhc2V0LCB3aWtpZGF0YV9pZCxjb25maXJtZWRfbG9nX2dyb3VwX251bWJlcikpICU+JQogICAgICAgIGFycmFuZ2UoZGF0ZV9hc2RhdGUpICMlPiUKICAgICAgICAjbXV0YXRlKCBjb25maXJtZWRfbG9nX3lfaGF0X3BlcmNlbnRfY2hhbmdlID0gYnJlYWtwb2ludHMoZm9ybXVsYT1jb25maXJtZWRfbG9nX3lfaGF0X3BlcmNlbnRfY2hhbmdlIH4gMSwgZGF0YT0uICkgJT4lIGZpdHRlZC52YWx1ZXMoKSApCgpwX2ludGVycG9sYXRpb240ZCA8LSB0ZXN0ICU+JQogICAgICAgICAgICAgICAgICAgIGdncGxvdCgpICsgCiAgICAgICAgICAgICAgICAgICAgICAgZ2VvbV9wb2ludCggYWVzKHg9ZGF0ZV9hc2RhdGUsIHk9Y29uZmlybWVkX2xvZywgY29sb3I9ZGF0YXNldCksIGFscGhhPS4zKSArCiAgICAgICAgICAgICAgICAgICAgICAgZ2VvbV9saW5lKCBhZXMoeD1kYXRlX2FzZGF0ZSwgeT1jb25maXJtZWRfbG9nX3lfaGF0LCBjb2xvcj1kYXRhc2V0LCBncm91cD1ncm91cCkpICsgIwogICAgICAgICAgICAgICAgICAgICAgICNnZW9tX2xpbmUoZGF0YT10ZW1wX2RmMiwgYWVzKHg9ZGF0ZV9hc2RhdGUsIHk9eV9oYXRfbWVhbiksIGNvbG9yPSJibGFjayIsIGxpbmV0eXBlID0gImRhc2hlZCIpICsKICAgICAgICAgICAgICAgICAgICAgICB0aGVtZV9idygpICsKICAgICAgICAgICAgICAgICAgICAgICBnZ3RpdGxlKCJNYW5oYXR0YW4gaXMgTmV3IFlvcmsgQ291bnR5IFE1MDA0MTYiKSArIGZhY2V0X3dyYXAofmRhdGFzZXQgICApICsgZ3VpZGVzKCBjb2xvciA9IEZBTFNFKQoKI1N0YXRlbiBJc2xhbmQgaXMgcmljaG1vbmQgY291bnR5IFExMTk5Nzc4NAp0ZXN0IDwtIGxoc19sb25nX2NsZWFuX2ltcHV0ZWQgJT4lIG11dGF0ZShncm91cD1wYXN0ZShkYXRhc2V0LHdpa2lkYXRhX2lkLGNvbmZpcm1lZF9sb2dfeV9oYXRfcGVyY2VudF9jaGFuZ2UpKSAlPiUgZmlsdGVyKHdpa2lkYXRhX2lkPT0iUTExOTk3Nzg0IikgJT4lICAjbm8gaGl0cz8KICAgICAgICBtdXRhdGUoZ3JvdXA9cGFzdGUoZGF0YXNldCwgd2lraWRhdGFfaWQsY29uZmlybWVkX2xvZ19ncm91cF9udW1iZXIpKSAlPiUKICAgICAgICBhcnJhbmdlKGRhdGVfYXNkYXRlKSAjJT4lCiAgICAgICAgI211dGF0ZSggY29uZmlybWVkX2xvZ195X2hhdF9wZXJjZW50X2NoYW5nZSA9IGJyZWFrcG9pbnRzKGZvcm11bGE9Y29uZmlybWVkX2xvZ195X2hhdF9wZXJjZW50X2NoYW5nZSB+IDEsIGRhdGE9LiApICU+JSBmaXR0ZWQudmFsdWVzKCkgKQoKcF9pbnRlcnBvbGF0aW9uNGUgPC0gdGVzdCAlPiUKICAgICAgICAgICAgICAgICAgICBnZ3Bsb3QoKSArIAogICAgICAgICAgICAgICAgICAgICAgIGdlb21fcG9pbnQoIGFlcyh4PWRhdGVfYXNkYXRlLCB5PWNvbmZpcm1lZF9sb2csIGNvbG9yPWRhdGFzZXQpLCBhbHBoYT0uMykgKwogICAgICAgICAgICAgICAgICAgICAgIGdlb21fbGluZSggYWVzKHg9ZGF0ZV9hc2RhdGUsIHk9Y29uZmlybWVkX2xvZ195X2hhdCwgY29sb3I9ZGF0YXNldCwgZ3JvdXA9Z3JvdXApKSArICMKICAgICAgICAgICAgICAgICAgICAgICAjZ2VvbV9saW5lKGRhdGE9dGVtcF9kZjIsIGFlcyh4PWRhdGVfYXNkYXRlLCB5PXlfaGF0X21lYW4pLCBjb2xvcj0iYmxhY2siLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSArCiAgICAgICAgICAgICAgICAgICAgICAgdGhlbWVfYncoKSArCiAgICAgICAgICAgICAgICAgICAgICAgZ2d0aXRsZSgiU3RhdGVuIElzbGFuZCAgUmljaG1vbmQgQ291bnR5IFExMTk5Nzc4NCIpICsgZmFjZXRfd3JhcCh+ZGF0YXNldCAgICkgKyBndWlkZXMoIGNvbG9yID0gRkFMU0UpCgpgYGAKCk5vdGUgdGhhdCBDU1NFIGlzIGNvbmZsYXRpbmcgYWxsIG9mIE5ldyBZb3JrIENpdHkgd2l0aCBNYW5oYXR0YW4vTmV3IFlvcmsgQ291bnR5LCBCaW5nIGlzIHRvbyBJIHRoaW5rCgpgYGB7ciwgZmlnLndpZHRoPTgsIGZpZy5oZWlnaHQ9Nix3YXJuaW5nPUZBTFNFLG1lc3NhZ2U9RkFMU0UsZXJyb3I9RkFMU0V9CnBfaW50ZXJwb2xhdGlvbjRhICsgcF9pbnRlcnBvbGF0aW9uNGIgKyBwX2ludGVycG9sYXRpb240YyArIHBfaW50ZXJwb2xhdGlvbjRkICsgcF9pbnRlcnBvbGF0aW9uNGUKYGBgCgoKCiMjIFBsb3RzIGJ5IENvdW50cmllcwoKYGBge3J9CmxpYnJhcnkoZGF0YS50YWJsZSkKZ2VvbmFtZXMgPC0gZnJlYWQoIi9tZWRpYS9za3luZXQyLzkwNTg4NGYwLTc1NDYtNDI3My05MDYxLTEyYTc5MDgzMGJlYi9yd2RfZ2l0aHViX3ByaXZhdGUvTkVTU2NvdmlkMTkvZGF0YV90ZW1wL2FsbENvdW50cmllcy50eHQiLCBzZXA9Ilx0IikgJT4lIG11dGF0ZV9pZihpcy5udW1lcmljLGFzLmNoYXJhY3RlcikgJT4lIG11dGF0ZV9pZihpcy5mYWN0b3IsYXMuY2hhcmFjdGVyKQpkaW0oZ2VvbmFtZXMpICMxMiwwMDYsNDI2CgpnZW9uYW1lc19zbWFsbCA8LSBnZW9uYW1lcyAlPiUgZHBseXI6OnNlbGVjdChnZW9uYW1laWQ9VjEsIG5hbWVfdGV4dD1WMikgJT4lIGlubmVyX2pvaW4oIGxoc19sb25nX2NsZWFuX2ltcHV0ZWQgJT4lIGRwbHlyOjpzZWxlY3QoZ2VvbmFtZWlkKSAlPiUgZGlzdGluY3QoKSApCmRpbShnZW9uYW1lc19zbWFsbCkKCmBgYAoKIyMjIENvbmZpcm1lZApgYGB7ciwgZmlnLndpZHRoPTE2LCBmaWcuaGVpZ2h0PTEyLHdhcm5pbmc9RkFMU0UsbWVzc2FnZT1GQUxTRSxlcnJvcj1GQUxTRSwgcmVzdWx0cz0naGlkZSd9CnBfY29uZmlybWVkX2J5X2NvdW50cnkgPC0gbGhzX2xvbmdfY2xlYW5faW1wdXRlZCAlPiUKICAgICAgICAgICAgICAgICAgICAgICAgICBmaWx0ZXIoIWdpZCAlPiUgc3RyX2RldGVjdCgiXyIpICkgJT4lCiAgICAgICAgICAgICAgICAgICAgICAgICAgbGVmdF9qb2luKGdlb25hbWVzX3NtYWxsICApICU+JSBtdXRhdGUobmFtZV90ZXh0ICU+JSBhcy5mYWN0b3IoKSkgJT4lCiAgICAgICAgICAgICAgICAgICAgICAgICAgbXV0YXRlKGdyb3VwPXBhc3RlKGdpZF9nZW9uYW1laWRfd2lraWRhdGFfaWQsY29uZmlybWVkX2xvZ19ncm91cF9udW1iZXIpKSAlPiUKICAgICAgICAgICAgICAgICAgICAgICAgICBnZ3Bsb3QoKSArIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICNnZW9tX3BvaW50KCBhZXMoeD1kYXRlX2FzZGF0ZSwgeT1jb25maXJtZWRfbG9nLCBjb2xvcj1kYXRhc2V0KSwgYWxwaGE9LjMpICsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZW9tX2xpbmUoIGFlcyh4PWRhdGVfYXNkYXRlLCB5PWNvbmZpcm1lZF9sb2dfeV9oYXQsIGNvbG9yPWRhdGFzZXQsIGdyb3VwPWdyb3VwKSkgKyAjCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI2dlb21fbGluZShkYXRhPXRlbXBfZGYyLCBhZXMoeD1kYXRlX2FzZGF0ZSwgeT15X2hhdF9tZWFuKSwgY29sb3I9ImJsYWNrIiwgbGluZXR5cGUgPSAiZGFzaGVkIikgKwogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoZW1lX2J3KCkgKwogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdndGl0bGUoIkNvbmZpcm1lZCAobG9nKSBieSBDb3VudHJ5IikgKyBmYWNldF93cmFwKH5uYW1lX3RleHQgICApICsgZ3VpZGVzKCBjb2xvciA9IEZBTFNFKSArCiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGVtZSgKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RyaXAuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKQogICAgICAgICAgICAgICAgICAgICAgICAgICAgLCAgc3RyaXAudGV4dC54ID0gZWxlbWVudF9ibGFuaygpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICApCmBgYAoKYGBge3J9CnBfY29uZmlybWVkX2J5X2NvdW50cnkKYGBgCgojIyMgRGVhdGhzCgpgYGB7ciwgZmlnLndpZHRoPTE2LCBmaWcuaGVpZ2h0PTEyLHdhcm5pbmc9RkFMU0UsbWVzc2FnZT1GQUxTRSxlcnJvcj1GQUxTRSwgcmVzdWx0cz0naGlkZSd9CnBfZGVhdGhzX2J5X2NvdW50cnkgPC0gbGhzX2xvbmdfY2xlYW5faW1wdXRlZCAlPiUKICAgICAgICAgICAgICAgICAgICAgICAgICBmaWx0ZXIoIWdpZCAlPiUgc3RyX2RldGVjdCgiXyIpICkgJT4lCiAgICAgICAgICAgICAgICAgICAgICAgICAgbGVmdF9qb2luKGdlb25hbWVzX3NtYWxsICApICU+JSBtdXRhdGUobmFtZV90ZXh0ICU+JSBhcy5mYWN0b3IoKSkgJT4lCiAgICAgICAgICAgICAgICAgICAgICAgICAgbXV0YXRlKGdyb3VwPXBhc3RlKGdpZF9nZW9uYW1laWRfd2lraWRhdGFfaWQsY29uZmlybWVkX2xvZ19ncm91cF9udW1iZXIpKSAlPiUKICAgICAgICAgICAgICAgICAgICAgICAgICBnZ3Bsb3QoKSArIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICNnZW9tX3BvaW50KCBhZXMoeD1kYXRlX2FzZGF0ZSwgeT1kZWF0aHNfbG9nX3lfaGF0LCBjb2xvcj1kYXRhc2V0KSwgYWxwaGE9LjMpICsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZW9tX2xpbmUoIGFlcyh4PWRhdGVfYXNkYXRlLCB5PWRlYXRoc19sb2dfeV9oYXQsIGNvbG9yPWRhdGFzZXQsIGdyb3VwPWdyb3VwKSkgKyAjCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI2dlb21fbGluZShkYXRhPXRlbXBfZGYyLCBhZXMoeD1kYXRlX2FzZGF0ZSwgeT15X2hhdF9tZWFuKSwgY29sb3I9ImJsYWNrIiwgbGluZXR5cGUgPSAiZGFzaGVkIikgKwogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoZW1lX2J3KCkgKwogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdndGl0bGUoIkRlYXRocyAobG9nKSBieSBDb3VudHJ5IikgKyBmYWNldF93cmFwKH5uYW1lX3RleHQgICApICsgZ3VpZGVzKCBjb2xvciA9IEZBTFNFKSArCiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGVtZSgKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RyaXAuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKQogICAgICAgICAgICAgICAgICAgICAgICAgICAgLCAgc3RyaXAudGV4dC54ID0gZWxlbWVudF9ibGFuaygpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICApCmBgYAoKYGBge3IsIGZpZy53aWR0aD0xNiwgZmlnLmhlaWdodD0xMn0KcF9kZWF0aHNfYnlfY291bnRyeQpgYGAKCiMjIyBUZXN0cwoKYGBge3IsIGZpZy53aWR0aD0xNiwgZmlnLmhlaWdodD0xMix3YXJuaW5nPUZBTFNFLG1lc3NhZ2U9RkFMU0UsZXJyb3I9RkFMU0UsIHJlc3VsdHM9J2hpZGUnfQpwX3Rlc3RlZF9wZW9wbGVfYnlfY291bnRyeSA8LSBsaHNfbG9uZ19jbGVhbl9pbXB1dGVkICU+JQogICAgICAgICAgICAgICAgICAgICAgICAgIGZpbHRlcighZ2lkICU+JSBzdHJfZGV0ZWN0KCJfIikgKSAlPiUKICAgICAgICAgICAgICAgICAgICAgICAgICBsZWZ0X2pvaW4oZ2VvbmFtZXNfc21hbGwgICkgJT4lIG11dGF0ZShuYW1lX3RleHQgJT4lIGFzLmZhY3RvcigpKSAlPiUKICAgICAgICAgICAgICAgICAgICAgICAgICBtdXRhdGUoZ3JvdXA9cGFzdGUoZ2lkX2dlb25hbWVpZF93aWtpZGF0YV9pZCxjb25maXJtZWRfbG9nX2dyb3VwX251bWJlcikpICU+JQogICAgICAgICAgICAgICAgICAgICAgICAgIGdncGxvdCgpICsgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI2dlb21fcG9pbnQoIGFlcyh4PWRhdGVfYXNkYXRlLCB5PXRlc3RlZF9wZW9wbGVfbG9nX3lfaGF0LCBjb2xvcj1kYXRhc2V0KSwgYWxwaGE9LjMpICsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZW9tX2xpbmUoIGFlcyh4PWRhdGVfYXNkYXRlLCB5PXRlc3RlZF9wZW9wbGVfbG9nX3lfaGF0LCBjb2xvcj1kYXRhc2V0LCBncm91cD1ncm91cCkpICsgIwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICNnZW9tX2xpbmUoZGF0YT10ZW1wX2RmMiwgYWVzKHg9ZGF0ZV9hc2RhdGUsIHk9eV9oYXRfbWVhbiksIGNvbG9yPSJibGFjayIsIGxpbmV0eXBlID0gImRhc2hlZCIpICsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGVtZV9idygpICsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZ3RpdGxlKCJUZXN0cyAobG9nKSBieSBDb3VudHJ5IikgKyBmYWNldF93cmFwKH5uYW1lX3RleHQgICApICsgZ3VpZGVzKCBjb2xvciA9IEZBTFNFKSArCiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGVtZSgKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RyaXAuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKQogICAgICAgICAgICAgICAgICAgICAgICAgICAgLCAgc3RyaXAudGV4dC54ID0gZWxlbWVudF9ibGFuaygpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICApCmBgYAoKYGBge3IsIGZpZy53aWR0aD0xNiwgZmlnLmhlaWdodD0xMn0KcF90ZXN0ZWRfcGVvcGxlX2J5X2NvdW50cnkKYGBgCgoKIyMgSW50ZXJwb2xhdGlvbiBvZiBSYXRlIG9mIENoYW5nZQoKIyMgUGxvdCBDb25maXJtZWQgQ3VydmVzIGZvciBTZWxlY3QgTG9jYXRpb25zCgpgYGB7ciwgZmlnLndpZHRoPTE2LCBmaWcuaGVpZ2h0PTEyLHdhcm5pbmc9RkFMU0UsbWVzc2FnZT1GQUxTRSxlcnJvcj1GQUxTRSwgcmVzdWx0cz0naGlkZSd9CgpsaWJyYXJ5KHBhdGNod29yaykKbGhzX2xvbmdfY2xlYW5faW1wdXRlZCA8LSByZWFkUkRTKCAiL21lZGlhL3NreW5ldDIvOTA1ODg0ZjAtNzU0Ni00MjczLTkwNjEtMTJhNzkwODMwYmViL3J3ZF9naXRodWJfcHJpdmF0ZS9ORVNTY292aWQxOS9kYXRhX3RlbXAvbGhzX2xvbmdfY2xlYW5faW1wdXRlZC5SZHMiKQpkaW0obGhzX2xvbmdfY2xlYW5faW1wdXRlZCkgIzQ1LDYwOSAjMzM3MDQzCgojd2Ugd2FudCB0aGUgY29sb3JzIHRvIGJlIGNvbnNpc3RlbnQgYnkgZGF0YXNldCB0b28gYnR3CgojIyMjIwojVVNBIFEzMAoKI2JwX3RlbXAgPC0gYnJlYWtwb2ludHMoZm9ybXVsYT1jb25maXJtZWRfbG9nX3lfaGF0X3BlcmNlbnRfY2hhbmdlIH4gMSwgZGF0YT10ZW1wX2RmICU+JSBtdXRhdGUoZ3JvdXA9cGFzdGUoZGF0YXNldCx3aWtpZGF0YV9pZCxjb25maXJtZWRfbG9nX3lfaGF0X3BlcmNlbnRfY2hhbmdlKSkgJT4lIGZpbHRlcih3aWtpZGF0YV9pZD09IlEzMCIpKQojY29uZmlybWVkX2xvZ195X2hhdF9wZXJjZW50X2NoYW5nZT1maXR0ZWQudmFsdWVzKGJwX3RlbXApCgp0ZXN0IDwtIGxoc19sb25nX2NsZWFuX2ltcHV0ZWQgJT4lCiAgICAgICAgbXV0YXRlKGdyb3VwPXBhc3RlKGRhdGFzZXQsd2lraWRhdGFfaWQsY29uZmlybWVkX2xvZ19ncm91cF9udW1iZXIpKSAlPiUKICAgICAgICBmaWx0ZXIod2lraWRhdGFfaWQ9PSJRMzAiKSAlPiUgCiAgICAgICAgYXJyYW5nZShkYXRlX2FzZGF0ZSkgICU+JQogICAgICAgIG11dGF0ZShkYXRlX2FzbnVtZXJpYyA9IGRhdGVfYXNkYXRlICU+JSBhcy5udW1lcmljKCkgKQoKI3J0MSA8LSBycGFydChmb3JtdWxhID0gY29uZmlybWVkX2xvZ195X2hhdF9wZXJjZW50X2NoYW5nZSB+IGRhdGVfYXNudW1lcmljLCBkYXRhPXRlc3QpCiNpbnRlcnBvbGF0ZWQgPSBkYXRhLmZyYW1lKGRhdGVfYXNudW1lcmljPW1pbih0ZXN0JGRhdGVfYXNudW1lcmljKTptYXgodGVzdCRkYXRlX2FzbnVtZXJpYykgKQojaW50ZXJwb2xhdGVkJGNvbmZpcm1lZF9sb2dfeV9oYXRfcGVyY2VudF9jaGFuZ2VfeV9oYXQgPC0gIHByZWRpY3QocnQxLCBuZXdkYXRhPWludGVycG9sYXRlZCkKI2ludGVycG9sYXRlZCRkYXRlX2FzZGF0ZSA8LSBhcy5EYXRlKGludGVycG9sYXRlZCRkYXRlX2FzbnVtZXJpYykKCnAwYSA8LSB0ZXN0ICU+JQogICAgICAgIGdncGxvdCgpICsgCiAgICAgICAgICAgZ2VvbV9wb2ludCggYWVzKHg9ZGF0ZV9hc2RhdGUsIHk9Y29uZmlybWVkX2xvZywgY29sb3I9ZGF0YXNldCksIGFscGhhPS4zKSArCiAgICAgICAgICAgZ2VvbV9saW5lKCBhZXMoeD1kYXRlX2FzZGF0ZSwgeT1jb25maXJtZWRfbG9nX3lfaGF0LCBjb2xvcj1kYXRhc2V0LCBncm91cD1ncm91cCkpICsgIwogICAgICAgICAgICNnZW9tX2xpbmUoZGF0YT10ZW1wX2RmMiwgYWVzKHg9ZGF0ZV9hc2RhdGUsIHk9eV9oYXRfbWVhbiksIGNvbG9yPSJibGFjayIsIGxpbmV0eXBlID0gImRhc2hlZCIpICsKICAgICAgICAgICB0aGVtZV9idygpICsKICAgICAgICAgICBnZ3RpdGxlKCJVU0EgUTMwIENvbmZpcm1lZCIpICMgKyBmYWNldF93cmFwKH5kYXRhc2V0KSAKCnAwYiA8LSB0ZXN0ICU+JQogICAgICAgZ2dwbG90KCkgKyAKICAgICAgICAgZ2VvbV9wb2ludCggYWVzKHg9ZGF0ZV9hc2RhdGUgLCB5PWNvbmZpcm1lZF9sb2dfeV9oYXRfcGVyY2VudF9jaGFuZ2UsIGNvbG9yPWRhdGFzZXQpLCBhbHBoYT0uMyApICsKICAgICAgICAgZ2VvbV9saW5lKGFlcyh4PWRhdGVfYXNkYXRlICwgeT1jb25maXJtZWRfbG9nX3lfaGF0X3BlcmNlbnRfY2hhbmdlX3lfaGF0ICksIGFscGhhPTEsIGNvbG9yPSJibGFjayIgICkgKwogICAgICAgICAjZ2VvbV9zbW9vdGgoIGFlcyh4PWRhdGVfYXNkYXRlICwgeT1jb25maXJtZWRfbG9nX3lfaGF0X3BlcmNlbnRfY2hhbmdlKSwgYWxwaGE9LjMsIHNwYW49LjA1KSArICMsIHNwYW49LjA1CiAgICAgICAgICNnZW9tX2xpbmUoIGFlcyh4PWRhdGVfYXNkYXRlLCB5PWNvbmZpcm1lZF9sb2dfeV9oYXQsIGNvbG9yPWRhdGFzZXQsIGdyb3VwPWdyb3VwKSkgKyAjCiAgICAgICAgICNnZW9tX2xpbmUoZGF0YT10ZW1wX2RmMiwgYWVzKHg9ZGF0ZV9hc2RhdGUsIHk9eV9oYXRfbWVhbiksIGNvbG9yPSJibGFjayIsIGxpbmV0eXBlID0gImRhc2hlZCIpICsKICAgICAgICAgdGhlbWVfYncoKSArCiAgICAgICAgIGdndGl0bGUoIlVTQSBRMzAgQ29uZmlybWVkIikgIyArIGZhY2V0X3dyYXAofmRhdGFzZXQpKyB5bGFiKCJEYWlseSBQZXJjZW50IENoYW5nZSBDb25maXJtZWQiKQoKI3AwYSAvIHAwYgoKCgojIyMjIwojQ2hpbmEgUTE0OAoKdGVzdCA8LSBsaHNfbG9uZ19jbGVhbl9pbXB1dGVkICU+JSBtdXRhdGUoZ3JvdXA9cGFzdGUoZGF0YXNldCx3aWtpZGF0YV9pZCxjb25maXJtZWRfbG9nX2dyb3VwX251bWJlcikpICU+JSBmaWx0ZXIod2lraWRhdGFfaWQ9PSJRMTQ4IikgJT4lIAogICAgICAgIG11dGF0ZShncm91cD1wYXN0ZShkYXRhc2V0LCB3aWtpZGF0YV9pZCxjb25maXJtZWRfbG9nX2dyb3VwX251bWJlcikpICU+JQogICAgICAgIGFycmFuZ2UoZGF0ZV9hc2RhdGUpICMlPiUKCnAxYSA8LSB0ZXN0ICU+JSAKZ2dwbG90KCkgKyAKICAgZ2VvbV9wb2ludCggYWVzKHg9ZGF0ZV9hc2RhdGUsIHk9Y29uZmlybWVkX2xvZywgY29sb3I9ZGF0YXNldCksIGFscGhhPS4zKSArCiAgIGdlb21fbGluZSggYWVzKHg9ZGF0ZV9hc2RhdGUsIHk9Y29uZmlybWVkX2xvZ195X2hhdCwgY29sb3I9ZGF0YXNldCwgZ3JvdXA9Z3JvdXApKSArICMKICAgI2dlb21fbGluZShkYXRhPXRlbXBfZGYyLCBhZXMoeD1kYXRlX2FzZGF0ZSwgeT15X2hhdF9tZWFuKSwgY29sb3I9ImJsYWNrIiwgbGluZXR5cGUgPSAiZGFzaGVkIikgKwogICB0aGVtZV9idygpICsKICAgZ2d0aXRsZSgiQ2hpbmEgUTE0OCBDb25maXJtZWQiKQoKcDFiIDwtIHRlc3QgJT4lCiAgICAgICBnZ3Bsb3QoKSArIAogICAgICAgICBnZW9tX3BvaW50KCBhZXMoeD1kYXRlX2FzZGF0ZSAsIHk9Y29uZmlybWVkX2xvZ195X2hhdF9wZXJjZW50X2NoYW5nZSwgY29sb3I9ZGF0YXNldCksIGFscGhhPS4zKSArCiAgICAgICAgIGdlb21fbGluZShhZXMoeD1kYXRlX2FzZGF0ZSAsIHk9Y29uZmlybWVkX2xvZ195X2hhdF9wZXJjZW50X2NoYW5nZV95X2hhdCApLCBhbHBoYT0xLCBjb2xvcj0iYmxhY2siKSArCiAgICAgICAgICNnZW9tX3Ntb290aCggYWVzKHg9ZGF0ZV9hc2RhdGUgLCB5PWNvbmZpcm1lZF9sb2dfeV9oYXRfcGVyY2VudF9jaGFuZ2UpLCBhbHBoYT0uMywgc3Bhbj0uMDUpICsgIywgc3Bhbj0uMDUKICAgICAgICAgI2dlb21fbGluZSggYWVzKHg9ZGF0ZV9hc2RhdGUsIHk9Y29uZmlybWVkX2xvZ195X2hhdCwgY29sb3I9ZGF0YXNldCwgZ3JvdXA9Z3JvdXApKSArICMKICAgICAgICAgI2dlb21fbGluZShkYXRhPXRlbXBfZGYyLCBhZXMoeD1kYXRlX2FzZGF0ZSwgeT15X2hhdF9tZWFuKSwgY29sb3I9ImJsYWNrIiwgbGluZXR5cGUgPSAiZGFzaGVkIikgKwogICAgICAgICB0aGVtZV9idygpICsKICAgZ2d0aXRsZSgiQ2hpbmEgUTE0OCBDb25maXJtZWQiKSsgeWxhYigiRGFpbHkgUGVyY2VudCBDaGFuZ2UgQ29uZmlybWVkIikKICAgCgojcDFhIC8gcDFiCgojSW5kaWEKIyJRNjY4IgoKdGVzdCA8LSBsaHNfbG9uZ19jbGVhbl9pbXB1dGVkICU+JSBtdXRhdGUoZ3JvdXA9cGFzdGUoZGF0YXNldCx3aWtpZGF0YV9pZCxjb25maXJtZWRfbG9nX3lfaGF0X3BlcmNlbnRfY2hhbmdlKSkgJT4lIGZpbHRlcih3aWtpZGF0YV9pZD09IlE2NjgiKSAlPiUgCiAgICAgICAgbXV0YXRlKGdyb3VwPXBhc3RlKGRhdGFzZXQsIHdpa2lkYXRhX2lkLGNvbmZpcm1lZF9sb2dfZ3JvdXBfbnVtYmVyKSkgJT4lCiAgICAgICAgYXJyYW5nZShkYXRlX2FzZGF0ZSkgIyU+JQogICAgICAgICNtdXRhdGUoIGNvbmZpcm1lZF9sb2dfeV9oYXRfcGVyY2VudF9jaGFuZ2UgPSBicmVha3BvaW50cyhmb3JtdWxhPWNvbmZpcm1lZF9sb2dfeV9oYXRfcGVyY2VudF9jaGFuZ2UgfiAxLCBkYXRhPS4gKSAlPiUgZml0dGVkLnZhbHVlcygpICkKCgpwMmEgPC0gdGVzdCAlPiUKZ2dwbG90KCkgKyAKICAgZ2VvbV9wb2ludCggYWVzKHg9ZGF0ZV9hc2RhdGUsIHk9Y29uZmlybWVkX2xvZywgY29sb3I9ZGF0YXNldCksIGFscGhhPS4zKSArCiAgIGdlb21fbGluZSggYWVzKHg9ZGF0ZV9hc2RhdGUsIHk9Y29uZmlybWVkX2xvZ195X2hhdCwgY29sb3I9ZGF0YXNldCwgZ3JvdXA9Z3JvdXApKSArICMKICAgI2dlb21fbGluZShkYXRhPXRlbXBfZGYyLCBhZXMoeD1kYXRlX2FzZGF0ZSwgeT15X2hhdF9tZWFuKSwgY29sb3I9ImJsYWNrIiwgbGluZXR5cGUgPSAiZGFzaGVkIikgKwogICB0aGVtZV9idygpICsKICAgZ2d0aXRsZSgiSW5kaWEgUTY2OCBDb25maXJtZWQiKQoKcDJiIDwtIHRlc3QgJT4lCiAgICAgICBnZ3Bsb3QoKSArIAogICAgICAgICBnZW9tX3BvaW50KCBhZXMoeD1kYXRlX2FzZGF0ZSAsIHk9Y29uZmlybWVkX2xvZ195X2hhdF9wZXJjZW50X2NoYW5nZSwgY29sb3I9ZGF0YXNldCksIGFscGhhPS4zKSArCiAgICAgICAgIGdlb21fbGluZShhZXMoeD1kYXRlX2FzZGF0ZSAsIHk9Y29uZmlybWVkX2xvZ195X2hhdF9wZXJjZW50X2NoYW5nZV95X2hhdCApLCBhbHBoYT0xLCBjb2xvcj0iYmxhY2siKSArCiAgICAgICAgICNnZW9tX3Ntb290aCggYWVzKHg9ZGF0ZV9hc2RhdGUgLCB5PWNvbmZpcm1lZF9sb2dfeV9oYXRfcGVyY2VudF9jaGFuZ2UpLCBhbHBoYT0uMywgc3Bhbj0uMDUpICsgIywgc3Bhbj0uMDUKICAgICAgICAgI2dlb21fbGluZSggYWVzKHg9ZGF0ZV9hc2RhdGUsIHk9Y29uZmlybWVkX2xvZ195X2hhdCwgY29sb3I9ZGF0YXNldCwgZ3JvdXA9Z3JvdXApKSArICMKICAgICAgICAgI2dlb21fbGluZShkYXRhPXRlbXBfZGYyLCBhZXMoeD1kYXRlX2FzZGF0ZSwgeT15X2hhdF9tZWFuKSwgY29sb3I9ImJsYWNrIiwgbGluZXR5cGUgPSAiZGFzaGVkIikgKwogICAgICAgICB0aGVtZV9idygpICsKICAgZ2d0aXRsZSgiSW5kaWEgUTY2OCBDb25maXJtZWQiKSsgeWxhYigiRGFpbHkgUGVyY2VudCBDaGFuZ2UgQ29uZmlybWVkIikKIAogIAojcDJhIC8gcDJiCgoKCiNJdGFseQojIlEzOCIKCnRlc3QgPC0gbGhzX2xvbmdfY2xlYW5faW1wdXRlZCAlPiUgbXV0YXRlKGdyb3VwPXBhc3RlKGRhdGFzZXQsd2lraWRhdGFfaWQsY29uZmlybWVkX2xvZ195X2hhdF9wZXJjZW50X2NoYW5nZSkpICU+JSBmaWx0ZXIod2lraWRhdGFfaWQ9PSJRMzgiKSAlPiUgCiAgICAgICAgbXV0YXRlKGdyb3VwPXBhc3RlKGRhdGFzZXQsIHdpa2lkYXRhX2lkLGNvbmZpcm1lZF9sb2dfZ3JvdXBfbnVtYmVyKSkgJT4lCiAgICAgICAgYXJyYW5nZShkYXRlX2FzZGF0ZSkgIyU+JQogICAgICAgICNtdXRhdGUoIGNvbmZpcm1lZF9sb2dfeV9oYXRfcGVyY2VudF9jaGFuZ2UgPSBicmVha3BvaW50cyhmb3JtdWxhPWNvbmZpcm1lZF9sb2dfeV9oYXRfcGVyY2VudF9jaGFuZ2UgfiAxLCBkYXRhPS4gKSAlPiUgZml0dGVkLnZhbHVlcygpICkKCgpwNGEgPC0gdGVzdCAlPiUKZ2dwbG90KCkgKyAKICAgZ2VvbV9wb2ludCggYWVzKHg9ZGF0ZV9hc2RhdGUsIHk9Y29uZmlybWVkX2xvZywgY29sb3I9ZGF0YXNldCksIGFscGhhPS4zKSArCiAgIGdlb21fbGluZSggYWVzKHg9ZGF0ZV9hc2RhdGUsIHk9Y29uZmlybWVkX2xvZ195X2hhdCwgY29sb3I9ZGF0YXNldCwgZ3JvdXA9Z3JvdXApKSArICMKICAgI2dlb21fbGluZShkYXRhPXRlbXBfZGYyLCBhZXMoeD1kYXRlX2FzZGF0ZSwgeT15X2hhdF9tZWFuKSwgY29sb3I9ImJsYWNrIiwgbGluZXR5cGUgPSAiZGFzaGVkIikgKwogICB0aGVtZV9idygpICsKICAgZ2d0aXRsZSgiSXRhbHkgUTM4IENvbmZpcm1lZCIpCgpwNGIgPC0gdGVzdCAlPiUKICAgICAgIGdncGxvdCgpICsgCiAgICAgICAgIGdlb21fcG9pbnQoIGFlcyh4PWRhdGVfYXNkYXRlICwgeT1jb25maXJtZWRfbG9nX3lfaGF0X3BlcmNlbnRfY2hhbmdlLCBjb2xvcj1kYXRhc2V0KSwgYWxwaGE9LjMpICsKICAgICAgICAgZ2VvbV9saW5lKGFlcyh4PWRhdGVfYXNkYXRlICwgeT1jb25maXJtZWRfbG9nX3lfaGF0X3BlcmNlbnRfY2hhbmdlX3lfaGF0ICksIGFscGhhPTEsIGNvbG9yPSJibGFjayIpICsKICAgICAgICAgI2dlb21fc21vb3RoKCBhZXMoeD1kYXRlX2FzZGF0ZSAsIHk9Y29uZmlybWVkX2xvZ195X2hhdF9wZXJjZW50X2NoYW5nZSksIGFscGhhPS4zLCBzcGFuPS4wNSkgKyAjLCBzcGFuPS4wNQogICAgICAgICAjZ2VvbV9saW5lKCBhZXMoeD1kYXRlX2FzZGF0ZSwgeT1jb25maXJtZWRfbG9nX3lfaGF0LCBjb2xvcj1kYXRhc2V0LCBncm91cD1ncm91cCkpICsgIwogICAgICAgICAjZ2VvbV9saW5lKGRhdGE9dGVtcF9kZjIsIGFlcyh4PWRhdGVfYXNkYXRlLCB5PXlfaGF0X21lYW4pLCBjb2xvcj0iYmxhY2siLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSArCiAgICAgICAgIHRoZW1lX2J3KCkgKwogICBnZ3RpdGxlKCJJdGFseSBRMzggQ29uZmlybWVkIikrIHlsYWIoIkRhaWx5IFBlcmNlbnQgQ2hhbmdlIENvbmZpcm1lZCIpCiAgIAogICAgCiNwNGEgLyBwNGIKCgoKI1NvdXRoIEtvcmVhCiMiUTg4NCIKCnRlc3QgPC0gbGhzX2xvbmdfY2xlYW5faW1wdXRlZCAlPiUgbXV0YXRlKGdyb3VwPXBhc3RlKGRhdGFzZXQsd2lraWRhdGFfaWQsY29uZmlybWVkX2xvZ195X2hhdF9wZXJjZW50X2NoYW5nZSkpICU+JSBmaWx0ZXIod2lraWRhdGFfaWQ9PSJRODg0IikgJT4lIAogICAgICAgIG11dGF0ZShncm91cD1wYXN0ZShkYXRhc2V0LCB3aWtpZGF0YV9pZCxjb25maXJtZWRfbG9nX2dyb3VwX251bWJlcikpICU+JQogICAgICAgIGFycmFuZ2UoZGF0ZV9hc2RhdGUpICMlPiUKICAgICAgICAjbXV0YXRlKCBjb25maXJtZWRfbG9nX3lfaGF0X3BlcmNlbnRfY2hhbmdlID0gYnJlYWtwb2ludHMoZm9ybXVsYT1jb25maXJtZWRfbG9nX3lfaGF0X3BlcmNlbnRfY2hhbmdlIH4gMSwgZGF0YT0uICkgJT4lIGZpdHRlZC52YWx1ZXMoKSApCgoKcDVhIDwtIHRlc3QgJT4lCmdncGxvdCgpICsgCiAgIGdlb21fcG9pbnQoIGFlcyh4PWRhdGVfYXNkYXRlLCB5PWNvbmZpcm1lZF9sb2csIGNvbG9yPWRhdGFzZXQpLCBhbHBoYT0uMykgKwogICBnZW9tX2xpbmUoIGFlcyh4PWRhdGVfYXNkYXRlLCB5PWNvbmZpcm1lZF9sb2dfeV9oYXQsIGNvbG9yPWRhdGFzZXQsIGdyb3VwPWdyb3VwKSkgKyAjCiAgICNnZW9tX2xpbmUoZGF0YT10ZW1wX2RmMiwgYWVzKHg9ZGF0ZV9hc2RhdGUsIHk9eV9oYXRfbWVhbiksIGNvbG9yPSJibGFjayIsIGxpbmV0eXBlID0gImRhc2hlZCIpICsKICAgdGhlbWVfYncoKSArCiAgIGdndGl0bGUoIlNvdXRoIEtvcmVhIFE4ODQgIENvbmZpcm1lZCIpCgpwNWIgPC0gdGVzdCAlPiUKICAgICAgIGdncGxvdCgpICsgCiAgICAgICAgIGdlb21fcG9pbnQoIGFlcyh4PWRhdGVfYXNkYXRlICwgeT1jb25maXJtZWRfbG9nX3lfaGF0X3BlcmNlbnRfY2hhbmdlLCBjb2xvcj1kYXRhc2V0KSwgYWxwaGE9LjMpICsKICAgICAgICAgZ2VvbV9saW5lKGFlcyh4PWRhdGVfYXNkYXRlICwgeT1jb25maXJtZWRfbG9nX3lfaGF0X3BlcmNlbnRfY2hhbmdlX3lfaGF0ICksIGFscGhhPTEsIGNvbG9yPSJibGFjayIpICsKICAgICAgICAgI2dlb21fc21vb3RoKCBhZXMoeD1kYXRlX2FzZGF0ZSAsIHk9Y29uZmlybWVkX2xvZ195X2hhdF9wZXJjZW50X2NoYW5nZSksIGFscGhhPS4zLCBzcGFuPS4wNSkgKyAjLCBzcGFuPS4wNQogICAgICAgICAjZ2VvbV9saW5lKCBhZXMoeD1kYXRlX2FzZGF0ZSwgeT1jb25maXJtZWRfbG9nX3lfaGF0LCBjb2xvcj1kYXRhc2V0LCBncm91cD1ncm91cCkpICsgIwogICAgICAgICAjZ2VvbV9saW5lKGRhdGE9dGVtcF9kZjIsIGFlcyh4PWRhdGVfYXNkYXRlLCB5PXlfaGF0X21lYW4pLCBjb2xvcj0iYmxhY2siLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSArCiAgICAgICAgIHRoZW1lX2J3KCkgKwogICBnZ3RpdGxlKCJTb3V0aCBLb3JlYSBRODg0IENvbmZpcm1lZCIpICsgeWxhYigiRGFpbHkgUGVyY2VudCBDaGFuZ2UgQ29uZmlybWVkIikKICAgCiAgICAKI3A1YSAvIHA1YgpgYGAKCgoKYGBge3IsIGZpZy53aWR0aD0xMiwgZmlnLmhlaWdodD02ICx3YXJuaW5nPUZBTFNFLG1lc3NhZ2U9RkFMU0UsZXJyb3I9RkFMU0V9CihwMGEgKyBwMWEgKyBwMmEgKSAvIChwMGIgKyBwMWIgKyBwMmIgKQpgYGAKCmBgYHtyLCBmaWcud2lkdGg9MTIsIGZpZy5oZWlnaHQ9NiAsd2FybmluZz1GQUxTRSxtZXNzYWdlPUZBTFNFLGVycm9yPUZBTFNFfQooIHA0YSArIHA1YSkgLyAoIHA0YiArIHA1YikKYGBgCgpgYGB7cn0KCgp0ZXN0IDwtIGxoc19sb25nX2NsZWFuX2ltcHV0ZWQgJT4lIG11dGF0ZShncm91cD1wYXN0ZShkYXRhc2V0LHdpa2lkYXRhX2lkLGNvbmZpcm1lZF9sb2dfeV9oYXRfcGVyY2VudF9jaGFuZ2UpKSAlPiUgZmlsdGVyKHdpa2lkYXRhX2lkPT0iUTE0MzkiKSAlPiUgCiAgICAgICAgbXV0YXRlKGdyb3VwPXBhc3RlKGRhdGFzZXQsIHdpa2lkYXRhX2lkLGNvbmZpcm1lZF9sb2dfZ3JvdXBfbnVtYmVyKSkgJT4lCiAgICAgICAgYXJyYW5nZShkYXRlX2FzZGF0ZSkgIyU+JQogICAgICAgICNtdXRhdGUoIGNvbmZpcm1lZF9sb2dfeV9oYXRfcGVyY2VudF9jaGFuZ2UgPSBicmVha3BvaW50cyhmb3JtdWxhPWNvbmZpcm1lZF9sb2dfeV9oYXRfcGVyY2VudF9jaGFuZ2UgfiAxLCBkYXRhPS4gKSAlPiUgZml0dGVkLnZhbHVlcygpICkKCgpwMGEgPC0gdGVzdCAlPiUKICAgICAgZ2dwbG90KCkgKyAKICAgICAgICAgZ2VvbV9wb2ludCggYWVzKHg9ZGF0ZV9hc2RhdGUsIHk9Y29uZmlybWVkX2xvZywgY29sb3I9ZGF0YXNldCksIGFscGhhPS4zKSArCiAgICAgICAgIGdlb21fbGluZSggYWVzKHg9ZGF0ZV9hc2RhdGUsIHk9Y29uZmlybWVkX2xvZ195X2hhdCwgY29sb3I9ZGF0YXNldCwgZ3JvdXA9Z3JvdXApKSArICMKICAgICAgICAgI2dlb21fbGluZShkYXRhPXRlbXBfZGYyLCBhZXMoeD1kYXRlX2FzZGF0ZSwgeT15X2hhdF9tZWFuKSwgY29sb3I9ImJsYWNrIiwgbGluZXR5cGUgPSAiZGFzaGVkIikgKwogICAgICAgICB0aGVtZV9idygpICsKICAgICAgICAgZ2d0aXRsZSgiVGV4YXMgUTE0MzkgQ29uZmlybWVkIikKCnAwYiA8LSB0ZXN0ICU+JQogICAgICAgZ2dwbG90KCkgKyAKICAgICAgICAgZ2VvbV9wb2ludCggYWVzKHg9ZGF0ZV9hc2RhdGUgLCB5PWNvbmZpcm1lZF9sb2dfeV9oYXRfcGVyY2VudF9jaGFuZ2UsIGNvbG9yPWRhdGFzZXQpLCBhbHBoYT0uMykgKwogICAgICAgICBnZW9tX2xpbmUoYWVzKHg9ZGF0ZV9hc2RhdGUgLCB5PWNvbmZpcm1lZF9sb2dfeV9oYXRfcGVyY2VudF9jaGFuZ2VfeV9oYXQgKSwgYWxwaGE9MSwgY29sb3I9ImJsYWNrIikgKwogICAgICAgICAjZ2VvbV9zbW9vdGgoIGFlcyh4PWRhdGVfYXNkYXRlICwgeT1jb25maXJtZWRfbG9nX3lfaGF0X3BlcmNlbnRfY2hhbmdlKSwgYWxwaGE9LjMsIHNwYW49LjA1KSArICMsIHNwYW49LjA1CiAgICAgICAgICNnZW9tX2xpbmUoIGFlcyh4PWRhdGVfYXNkYXRlLCB5PWNvbmZpcm1lZF9sb2dfeV9oYXQsIGNvbG9yPWRhdGFzZXQsIGdyb3VwPWdyb3VwKSkgKyAjCiAgICAgICAgICNnZW9tX2xpbmUoZGF0YT10ZW1wX2RmMiwgYWVzKHg9ZGF0ZV9hc2RhdGUsIHk9eV9oYXRfbWVhbiksIGNvbG9yPSJibGFjayIsIGxpbmV0eXBlID0gImRhc2hlZCIpICsKICAgICAgICAgdGhlbWVfYncoKSArCiAgICAgICAgIGdndGl0bGUoIlRleGFzIFExNDM5IENvbmZpcm1lZCIpICsgeWxpbSgwLDEwMCkrIHlsYWIoIkRhaWx5IFBlcmNlbnQgQ2hhbmdlIENvbmZpcm1lZCIpCgojQmV4YXIKIyJRMTY4NjEiCnRlc3QgPC0gbGhzX2xvbmdfY2xlYW5faW1wdXRlZCAlPiUgbXV0YXRlKGdyb3VwPXBhc3RlKGRhdGFzZXQsd2lraWRhdGFfaWQsY29uZmlybWVkX2xvZ195X2hhdF9wZXJjZW50X2NoYW5nZSkpICU+JSBmaWx0ZXIod2lraWRhdGFfaWQ9PSJRMTY4NjEiKSAlPiUgCiAgICAgICAgbXV0YXRlKGdyb3VwPXBhc3RlKGRhdGFzZXQsIHdpa2lkYXRhX2lkLGNvbmZpcm1lZF9sb2dfZ3JvdXBfbnVtYmVyKSkgJT4lCiAgICAgICAgYXJyYW5nZShkYXRlX2FzZGF0ZSkgIyU+JQogICAgICAgICNtdXRhdGUoIGNvbmZpcm1lZF9sb2dfeV9oYXRfcGVyY2VudF9jaGFuZ2UgPSBicmVha3BvaW50cyhmb3JtdWxhPWNvbmZpcm1lZF9sb2dfeV9oYXRfcGVyY2VudF9jaGFuZ2UgfiAxLCBkYXRhPS4gKSAlPiUgZml0dGVkLnZhbHVlcygpICkKcDFhIDwtIHRlc3QgJT4lCiAgICAgIGdncGxvdCgpICsgCiAgICAgICAgIGdlb21fcG9pbnQoIGFlcyh4PWRhdGVfYXNkYXRlLCB5PWNvbmZpcm1lZF9sb2csIGNvbG9yPWRhdGFzZXQpLCBhbHBoYT0uMykgKwogICAgICAgICBnZW9tX2xpbmUoIGFlcyh4PWRhdGVfYXNkYXRlLCB5PWNvbmZpcm1lZF9sb2dfeV9oYXQsIGNvbG9yPWRhdGFzZXQsIGdyb3VwPWdyb3VwKSkgKyAjCiAgICAgICAgICNnZW9tX2xpbmUoZGF0YT10ZW1wX2RmMiwgYWVzKHg9ZGF0ZV9hc2RhdGUsIHk9eV9oYXRfbWVhbiksIGNvbG9yPSJibGFjayIsIGxpbmV0eXBlID0gImRhc2hlZCIpICsKICAgICAgICAgdGhlbWVfYncoKSArCiAgICAgICAgIGdndGl0bGUoIkJleGFyIENvdW50eSBRMTY4NjEgQ29uZmlybWVkIikKcDFiIDwtIHRlc3QgJT4lCiAgICAgICBnZ3Bsb3QoKSArIAogICAgICAgICBnZW9tX3BvaW50KCBhZXMoeD1kYXRlX2FzZGF0ZSAsIHk9Y29uZmlybWVkX2xvZ195X2hhdF9wZXJjZW50X2NoYW5nZSwgY29sb3I9ZGF0YXNldCksIGFscGhhPS4zKSArCiAgICAgICAgIGdlb21fbGluZShhZXMoeD1kYXRlX2FzZGF0ZSAsIHk9Y29uZmlybWVkX2xvZ195X2hhdF9wZXJjZW50X2NoYW5nZV95X2hhdCApLCBhbHBoYT0xLCBjb2xvcj0iYmxhY2siKSArCiAgICAgICAgICNnZW9tX3Ntb290aCggYWVzKHg9ZGF0ZV9hc2RhdGUgLCB5PWNvbmZpcm1lZF9sb2dfeV9oYXRfcGVyY2VudF9jaGFuZ2UpLCBhbHBoYT0uMywgc3Bhbj0uMDUpICsgIywgc3Bhbj0uMDUKICAgICAgICAgI2dlb21fbGluZSggYWVzKHg9ZGF0ZV9hc2RhdGUsIHk9Y29uZmlybWVkX2xvZ195X2hhdCwgY29sb3I9ZGF0YXNldCwgZ3JvdXA9Z3JvdXApKSArICMKICAgICAgICAgI2dlb21fbGluZShkYXRhPXRlbXBfZGYyLCBhZXMoeD1kYXRlX2FzZGF0ZSwgeT15X2hhdF9tZWFuKSwgY29sb3I9ImJsYWNrIiwgbGluZXR5cGUgPSAiZGFzaGVkIikgKwogICAgICAgICB0aGVtZV9idygpICsKICAgZ2d0aXRsZSgiQmV4YXIgQ291bnR5IFExNjg2MSBDb25maXJtZWQiKSArIHlsaW0oMCwxMDApKyB5bGFiKCJEYWlseSBQZXJjZW50IENoYW5nZSBDb25maXJtZWQiKQoKI0NhbGlmb3JuaWEKdGVzdCA8LSBsaHNfbG9uZ19jbGVhbl9pbXB1dGVkICU+JSBtdXRhdGUoZ3JvdXA9cGFzdGUoZGF0YXNldCx3aWtpZGF0YV9pZCxjb25maXJtZWRfbG9nX3lfaGF0X3BlcmNlbnRfY2hhbmdlKSkgJT4lIGZpbHRlcih3aWtpZGF0YV9pZD09IlE5OSIpICU+JSAKICAgICAgICBtdXRhdGUoZ3JvdXA9cGFzdGUoZGF0YXNldCwgd2lraWRhdGFfaWQsY29uZmlybWVkX2xvZ19ncm91cF9udW1iZXIpKSAlPiUKICAgICAgICBhcnJhbmdlKGRhdGVfYXNkYXRlKSAjJT4lCiAgICAgICAgI211dGF0ZSggY29uZmlybWVkX2xvZ195X2hhdF9wZXJjZW50X2NoYW5nZSA9IGJyZWFrcG9pbnRzKGZvcm11bGE9Y29uZmlybWVkX2xvZ195X2hhdF9wZXJjZW50X2NoYW5nZSB+IDEsIGRhdGE9LiApICU+JSBmaXR0ZWQudmFsdWVzKCkgKQpwMmEgPC0gdGVzdCAlPiUKICAgICAgZ2dwbG90KCkgKyAKICAgICAgICAgZ2VvbV9wb2ludCggYWVzKHg9ZGF0ZV9hc2RhdGUsIHk9Y29uZmlybWVkX2xvZywgY29sb3I9ZGF0YXNldCksIGFscGhhPS4zKSArCiAgICAgICAgIGdlb21fbGluZSggYWVzKHg9ZGF0ZV9hc2RhdGUsIHk9Y29uZmlybWVkX2xvZ195X2hhdCwgY29sb3I9ZGF0YXNldCwgZ3JvdXA9Z3JvdXApKSArICMKICAgICAgICAgI2dlb21fbGluZShkYXRhPXRlbXBfZGYyLCBhZXMoeD1kYXRlX2FzZGF0ZSwgeT15X2hhdF9tZWFuKSwgY29sb3I9ImJsYWNrIiwgbGluZXR5cGUgPSAiZGFzaGVkIikgKwogICAgICAgICB0aGVtZV9idygpICsKICAgICAgICAgZ2d0aXRsZSgiQ2FsaWZvcm5pYSBROTkgQ29uZmlybWVkIikKcDJiIDwtIHRlc3QgJT4lCiAgICAgICBnZ3Bsb3QoKSArIAogICAgICAgICBnZW9tX3BvaW50KCBhZXMoeD1kYXRlX2FzZGF0ZSAsIHk9Y29uZmlybWVkX2xvZ195X2hhdF9wZXJjZW50X2NoYW5nZSwgY29sb3I9ZGF0YXNldCksIGFscGhhPS4zKSArCiAgICAgICAgIGdlb21fbGluZShhZXMoeD1kYXRlX2FzZGF0ZSAsIHk9Y29uZmlybWVkX2xvZ195X2hhdF9wZXJjZW50X2NoYW5nZV95X2hhdCApLCBhbHBoYT0xLCBjb2xvcj0iYmxhY2siKSArCiAgICAgICAgICNnZW9tX3Ntb290aCggYWVzKHg9ZGF0ZV9hc2RhdGUgLCB5PWNvbmZpcm1lZF9sb2dfeV9oYXRfcGVyY2VudF9jaGFuZ2UpLCBhbHBoYT0uMywgc3Bhbj0uMDUpICsgIywgc3Bhbj0uMDUKICAgICAgICAgI2dlb21fbGluZSggYWVzKHg9ZGF0ZV9hc2RhdGUsIHk9Y29uZmlybWVkX2xvZ195X2hhdCwgY29sb3I9ZGF0YXNldCwgZ3JvdXA9Z3JvdXApKSArICMKICAgICAgICAgI2dlb21fbGluZShkYXRhPXRlbXBfZGYyLCBhZXMoeD1kYXRlX2FzZGF0ZSwgeT15X2hhdF9tZWFuKSwgY29sb3I9ImJsYWNrIiwgbGluZXR5cGUgPSAiZGFzaGVkIikgKwogICAgICAgICB0aGVtZV9idygpICsKICAgICAgICAgZ2d0aXRsZSgiQ2FsaWZvcm5pYSBROTkgQ29uZmlybWVkIikgKyB5bGltKDAsMTAwKSsgeWxhYigiRGFpbHkgUGVyY2VudCBDaGFuZ2UgQ29uZmlybWVkIikKCiNTYW4gRGllZ28gQ291bnR5IChRMTA4MTQzKQp0ZXN0IDwtIGxoc19sb25nX2NsZWFuX2ltcHV0ZWQgJT4lIG11dGF0ZShncm91cD1wYXN0ZShkYXRhc2V0LHdpa2lkYXRhX2lkLGNvbmZpcm1lZF9sb2dfeV9oYXRfcGVyY2VudF9jaGFuZ2UpKSAlPiUgZmlsdGVyKHdpa2lkYXRhX2lkPT0iUTEwODE0MyIpICU+JSAKICAgICAgICBtdXRhdGUoZ3JvdXA9cGFzdGUoZGF0YXNldCwgd2lraWRhdGFfaWQsY29uZmlybWVkX2xvZ19ncm91cF9udW1iZXIpKSAlPiUKICAgICAgICBhcnJhbmdlKGRhdGVfYXNkYXRlKSAjJT4lCiAgICAgICAgI211dGF0ZSggY29uZmlybWVkX2xvZ195X2hhdF9wZXJjZW50X2NoYW5nZSA9IGJyZWFrcG9pbnRzKGZvcm11bGE9Y29uZmlybWVkX2xvZ195X2hhdF9wZXJjZW50X2NoYW5nZSB+IDEsIGRhdGE9LiApICU+JSBmaXR0ZWQudmFsdWVzKCkgKQpwM2EgPC0gdGVzdCAlPiUKICAgICAgZ2dwbG90KCkgKyAKICAgICAgICAgZ2VvbV9wb2ludCggYWVzKHg9ZGF0ZV9hc2RhdGUsIHk9Y29uZmlybWVkX2xvZywgY29sb3I9ZGF0YXNldCksIGFscGhhPS4zKSArCiAgICAgICAgIGdlb21fbGluZSggYWVzKHg9ZGF0ZV9hc2RhdGUsIHk9Y29uZmlybWVkX2xvZ195X2hhdCwgY29sb3I9ZGF0YXNldCwgZ3JvdXA9Z3JvdXApKSArICMKICAgICAgICAgI2dlb21fbGluZShkYXRhPXRlbXBfZGYyLCBhZXMoeD1kYXRlX2FzZGF0ZSwgeT15X2hhdF9tZWFuKSwgY29sb3I9ImJsYWNrIiwgbGluZXR5cGUgPSAiZGFzaGVkIikgKwogICAgICAgICB0aGVtZV9idygpICsKICAgICAgICAgZ2d0aXRsZSgiU2FuIERpZWdvIENvdW50eSAoUTEwODE0MykgQ29uZmlybWVkIikKcDNiIDwtIHRlc3QgJT4lCiAgICAgICBnZ3Bsb3QoKSArIAogICAgICAgICBnZW9tX3BvaW50KCBhZXMoeD1kYXRlX2FzZGF0ZSAsIHk9Y29uZmlybWVkX2xvZ195X2hhdF9wZXJjZW50X2NoYW5nZSwgY29sb3I9ZGF0YXNldCksIGFscGhhPS4zKSArCiAgICAgICAgIGdlb21fbGluZShhZXMoeD1kYXRlX2FzZGF0ZSAsIHk9Y29uZmlybWVkX2xvZ195X2hhdF9wZXJjZW50X2NoYW5nZV95X2hhdCApLCBhbHBoYT0xLCBjb2xvcj0iYmxhY2siKSArCiAgICAgICAgICNnZW9tX3Ntb290aCggYWVzKHg9ZGF0ZV9hc2RhdGUgLCB5PWNvbmZpcm1lZF9sb2dfeV9oYXRfcGVyY2VudF9jaGFuZ2UpLCBhbHBoYT0uMywgc3Bhbj0uMDUpICsgIywgc3Bhbj0uMDUKICAgICAgICAgI2dlb21fbGluZSggYWVzKHg9ZGF0ZV9hc2RhdGUsIHk9Y29uZmlybWVkX2xvZ195X2hhdCwgY29sb3I9ZGF0YXNldCwgZ3JvdXA9Z3JvdXApKSArICMKICAgICAgICAgI2dlb21fbGluZShkYXRhPXRlbXBfZGYyLCBhZXMoeD1kYXRlX2FzZGF0ZSwgeT15X2hhdF9tZWFuKSwgY29sb3I9ImJsYWNrIiwgbGluZXR5cGUgPSAiZGFzaGVkIikgKwogICAgICAgICB0aGVtZV9idygpICsKICAgICAgICAgZ2d0aXRsZSgiU2FuIERpZWdvIENvdW50eSAoUTEwODE0MykgQ29uZmlybWVkIikgKyB5bGltKDAsMTAwKSsgeWxhYigiRGFpbHkgUGVyY2VudCBDaGFuZ2UgQ29uZmlybWVkIikKCiNGbG9yaWRhIChRODEyKQp0ZXN0IDwtIGxoc19sb25nX2NsZWFuX2ltcHV0ZWQgJT4lIG11dGF0ZShncm91cD1wYXN0ZShkYXRhc2V0LHdpa2lkYXRhX2lkLGNvbmZpcm1lZF9sb2dfeV9oYXRfcGVyY2VudF9jaGFuZ2UpKSAlPiUgZmlsdGVyKHdpa2lkYXRhX2lkPT0iUTgxMiIpICU+JSAKICAgICAgICBtdXRhdGUoZ3JvdXA9cGFzdGUoZGF0YXNldCwgd2lraWRhdGFfaWQsY29uZmlybWVkX2xvZ19ncm91cF9udW1iZXIpKSAlPiUKICAgICAgICBhcnJhbmdlKGRhdGVfYXNkYXRlKSAjJT4lCiAgICAgICAgI211dGF0ZSggY29uZmlybWVkX2xvZ195X2hhdF9wZXJjZW50X2NoYW5nZSA9IGJyZWFrcG9pbnRzKGZvcm11bGE9Y29uZmlybWVkX2xvZ195X2hhdF9wZXJjZW50X2NoYW5nZSB+IDEsIGRhdGE9LiApICU+JSBmaXR0ZWQudmFsdWVzKCkgKQpwNGEgPC0gdGVzdCAlPiUKICAgICAgZ2dwbG90KCkgKyAKICAgICAgICAgZ2VvbV9wb2ludCggYWVzKHg9ZGF0ZV9hc2RhdGUsIHk9Y29uZmlybWVkX2xvZywgY29sb3I9ZGF0YXNldCksIGFscGhhPS4zKSArCiAgICAgICAgIGdlb21fbGluZSggYWVzKHg9ZGF0ZV9hc2RhdGUsIHk9Y29uZmlybWVkX2xvZ195X2hhdCwgY29sb3I9ZGF0YXNldCwgZ3JvdXA9Z3JvdXApKSArICMKICAgICAgICAgI2dlb21fbGluZShkYXRhPXRlbXBfZGYyLCBhZXMoeD1kYXRlX2FzZGF0ZSwgeT15X2hhdF9tZWFuKSwgY29sb3I9ImJsYWNrIiwgbGluZXR5cGUgPSAiZGFzaGVkIikgKwogICAgICAgICB0aGVtZV9idygpICsKICAgICAgICAgZ2d0aXRsZSgiRmxvcmlkYSAoUTgxMikgQ29uZmlybWVkIikKcDRiIDwtIHRlc3QgJT4lCiAgICAgICBnZ3Bsb3QoKSArIAogICAgICAgICBnZW9tX3BvaW50KCBhZXMoeD1kYXRlX2FzZGF0ZSAsIHk9Y29uZmlybWVkX2xvZ195X2hhdF9wZXJjZW50X2NoYW5nZSwgY29sb3I9ZGF0YXNldCksIGFscGhhPS4zKSArCiAgICAgICAgIGdlb21fbGluZShhZXMoeD1kYXRlX2FzZGF0ZSAsIHk9Y29uZmlybWVkX2xvZ195X2hhdF9wZXJjZW50X2NoYW5nZV95X2hhdCApLCBhbHBoYT0xLCBjb2xvcj0iYmxhY2siKSArCiAgICAgICAgICNnZW9tX3Ntb290aCggYWVzKHg9ZGF0ZV9hc2RhdGUgLCB5PWNvbmZpcm1lZF9sb2dfeV9oYXRfcGVyY2VudF9jaGFuZ2UpLCBhbHBoYT0uMywgc3Bhbj0uMDUpICsgIywgc3Bhbj0uMDUKICAgICAgICAgI2dlb21fbGluZSggYWVzKHg9ZGF0ZV9hc2RhdGUsIHk9Y29uZmlybWVkX2xvZ195X2hhdCwgY29sb3I9ZGF0YXNldCwgZ3JvdXA9Z3JvdXApKSArICMKICAgICAgICAgI2dlb21fbGluZShkYXRhPXRlbXBfZGYyLCBhZXMoeD1kYXRlX2FzZGF0ZSwgeT15X2hhdF9tZWFuKSwgY29sb3I9ImJsYWNrIiwgbGluZXR5cGUgPSAiZGFzaGVkIikgKwogICAgICAgICB0aGVtZV9idygpICsKICAgICAgICAgZ2d0aXRsZSgiRmxvcmlkYSAoUTgxMikgQ29uZmlybWVkIikgKyB5bGltKDAsMTAwKSsgeWxhYigiRGFpbHkgUGVyY2VudCBDaGFuZ2UgQ29uZmlybWVkIikKCgojU3QuIEx1Y2llIENvdW50eSAoUTQ5NDU2NCkKdGVzdCA8LSBsaHNfbG9uZ19jbGVhbl9pbXB1dGVkICU+JSBtdXRhdGUoZ3JvdXA9cGFzdGUoZGF0YXNldCx3aWtpZGF0YV9pZCxjb25maXJtZWRfbG9nX3lfaGF0X3BlcmNlbnRfY2hhbmdlKSkgJT4lIGZpbHRlcih3aWtpZGF0YV9pZD09IlE0OTQ1NjQiKSAlPiUgCiAgICAgICAgbXV0YXRlKGdyb3VwPXBhc3RlKGRhdGFzZXQsIHdpa2lkYXRhX2lkLGNvbmZpcm1lZF9sb2dfZ3JvdXBfbnVtYmVyKSkgJT4lCiAgICAgICAgYXJyYW5nZShkYXRlX2FzZGF0ZSkgIyU+JQogICAgICAgICNtdXRhdGUoIGNvbmZpcm1lZF9sb2dfeV9oYXRfcGVyY2VudF9jaGFuZ2UgPSBicmVha3BvaW50cyhmb3JtdWxhPWNvbmZpcm1lZF9sb2dfeV9oYXRfcGVyY2VudF9jaGFuZ2UgfiAxLCBkYXRhPS4gKSAlPiUgZml0dGVkLnZhbHVlcygpICkKcDVhIDwtIHRlc3QgJT4lCiAgICAgIGdncGxvdCgpICsgCiAgICAgICAgIGdlb21fcG9pbnQoIGFlcyh4PWRhdGVfYXNkYXRlLCB5PWNvbmZpcm1lZF9sb2csIGNvbG9yPWRhdGFzZXQpLCBhbHBoYT0uMykgKwogICAgICAgICBnZW9tX2xpbmUoIGFlcyh4PWRhdGVfYXNkYXRlLCB5PWNvbmZpcm1lZF9sb2dfeV9oYXQsIGNvbG9yPWRhdGFzZXQsIGdyb3VwPWdyb3VwKSkgKyAjCiAgICAgICAgICNnZW9tX2xpbmUoZGF0YT10ZW1wX2RmMiwgYWVzKHg9ZGF0ZV9hc2RhdGUsIHk9eV9oYXRfbWVhbiksIGNvbG9yPSJibGFjayIsIGxpbmV0eXBlID0gImRhc2hlZCIpICsKICAgICAgICAgdGhlbWVfYncoKSArCiAgICAgICAgIGdndGl0bGUoIlN0LiBMdWNpZSBDb3VudHkgKFE0OTQ1NjQpIENvbmZpcm1lZCIpCnA1YiA8LSB0ZXN0ICU+JQogICAgICAgZ2dwbG90KCkgKyAKICAgICAgICAgZ2VvbV9wb2ludCggYWVzKHg9ZGF0ZV9hc2RhdGUgLCB5PWNvbmZpcm1lZF9sb2dfeV9oYXRfcGVyY2VudF9jaGFuZ2UsIGNvbG9yPWRhdGFzZXQpLCBhbHBoYT0uMykgKwogICAgICAgICBnZW9tX2xpbmUoYWVzKHg9ZGF0ZV9hc2RhdGUgLCB5PWNvbmZpcm1lZF9sb2dfeV9oYXRfcGVyY2VudF9jaGFuZ2VfeV9oYXQgKSwgYWxwaGE9MSwgY29sb3I9ImJsYWNrIikgKwogICAgICAgICAjZ2VvbV9zbW9vdGgoIGFlcyh4PWRhdGVfYXNkYXRlICwgeT1jb25maXJtZWRfbG9nX3lfaGF0X3BlcmNlbnRfY2hhbmdlKSwgYWxwaGE9LjMsIHNwYW49LjA1KSArICMsIHNwYW49LjA1CiAgICAgICAgICNnZW9tX2xpbmUoIGFlcyh4PWRhdGVfYXNkYXRlLCB5PWNvbmZpcm1lZF9sb2dfeV9oYXQsIGNvbG9yPWRhdGFzZXQsIGdyb3VwPWdyb3VwKSkgKyAjCiAgICAgICAgICNnZW9tX2xpbmUoZGF0YT10ZW1wX2RmMiwgYWVzKHg9ZGF0ZV9hc2RhdGUsIHk9eV9oYXRfbWVhbiksIGNvbG9yPSJibGFjayIsIGxpbmV0eXBlID0gImRhc2hlZCIpICsKICAgICAgICAgdGhlbWVfYncoKSArCiAgICAgICAgIGdndGl0bGUoIlN0LiBMdWNpZSBDb3VudHkgKFE0OTQ1NjQpIENvbmZpcm1lZCIpICsgeWxpbSgwLDEwMCkrIHlsYWIoIkRhaWx5IFBlcmNlbnQgQ2hhbmdlIENvbmZpcm1lZCIpCgoKYGBgCgpgYGB7ciwgZmlnLndpZHRoPTEyLCBmaWcuaGVpZ2h0PTYgLHdhcm5pbmc9RkFMU0UsbWVzc2FnZT1GQUxTRSxlcnJvcj1GQUxTRX0KI05vdCBjb3VudGluZyBzbG9wZXMgdGhhdCB3ZXJlIGludGVycG9sYXRlZCBvdXQgb2YgZG9tYWluIGZpeGVkIGNhbGlmb3JuaWEncyBwbG90CiggcDBhICsgcDFhICkgLyAoIHAwYiArIHAxYiApCmBgYAoKYGBge3IsIGZpZy53aWR0aD0xMiwgZmlnLmhlaWdodD02ICx3YXJuaW5nPUZBTFNFLG1lc3NhZ2U9RkFMU0UsZXJyb3I9RkFMU0V9CiggcDJhICsgcDNhICkgLyAoIHAyYiArIHAzYiApCmBgYAoKYGBge3IsIGZpZy53aWR0aD0xMiwgZmlnLmhlaWdodD02ICx3YXJuaW5nPUZBTFNFLG1lc3NhZ2U9RkFMU0UsZXJyb3I9RkFMU0V9CiggcDRhICsgcDVhKSAvICggcDRiICsgcDViKQpgYGAKCgojIyBQbG90IERlYXRoIEN1cnZlcyBmb3IgU2VsZWN0IExvY2F0aW9ucwoKU2hvdyBob3cgaW50ZXJwb2xhdGlvbiB3b3JrcyBvbiBkZWF0aHMKCmBgYHtyLCBmaWcud2lkdGg9MTYsIGZpZy5oZWlnaHQ9MTIsd2FybmluZz1GQUxTRSxtZXNzYWdlPUZBTFNFLGVycm9yPUZBTFNFLCByZXN1bHRzPSdoaWRlJ30KCnRlc3QgPC0gbGhzX2xvbmdfY2xlYW5faW1wdXRlZCAlPiUKICAgICAgICBtdXRhdGUoZ3JvdXA9cGFzdGUoZGF0YXNldCx3aWtpZGF0YV9pZCxkZWF0aHNfbG9nX2dyb3VwX251bWJlcikpICU+JQogICAgICAgIGZpbHRlcih3aWtpZGF0YV9pZD09IlEzMCIpICU+JSAKICAgICAgICBhcnJhbmdlKGRhdGVfYXNkYXRlKSAgJT4lCiAgICAgICAgbXV0YXRlKGRhdGVfYXNudW1lcmljID0gZGF0ZV9hc2RhdGUgJT4lIGFzLm51bWVyaWMoKSApCgpwMGEgPC0gdGVzdCAlPiUKICAgICAgICBnZ3Bsb3QoKSArIAogICAgICAgICAgIGdlb21fcG9pbnQoIGFlcyh4PWRhdGVfYXNkYXRlLCB5PWRlYXRoc19sb2csIGNvbG9yPWRhdGFzZXQpLCBhbHBoYT0uMykgKwogICAgICAgICAgIGdlb21fbGluZSggYWVzKHg9ZGF0ZV9hc2RhdGUsIHk9ZGVhdGhzX2xvZ195X2hhdCwgY29sb3I9ZGF0YXNldCwgZ3JvdXA9Z3JvdXApKSArICMKICAgICAgICAgICAjZ2VvbV9saW5lKGRhdGE9dGVtcF9kZjIsIGFlcyh4PWRhdGVfYXNkYXRlLCB5PXlfaGF0X21lYW4pLCBjb2xvcj0iYmxhY2siLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSArCiAgICAgICAgICAgdGhlbWVfYncoKSArCiAgICAgICAgICAgZ2d0aXRsZSgiVVNBIFEzMCBEZWF0aHMiKSAjICsgZmFjZXRfd3JhcCh+ZGF0YXNldCkgCgpwMGIgPC0gdGVzdCAlPiUKICAgICAgIGdncGxvdCgpICsgCiAgICAgICAgIGdlb21fcG9pbnQoIGFlcyh4PWRhdGVfYXNkYXRlICwgeT1kZWF0aHNfbG9nX3lfaGF0X3BlcmNlbnRfY2hhbmdlLCBjb2xvcj1kYXRhc2V0KSwgYWxwaGE9LjMgKSArCiAgICAgICAgIGdlb21fbGluZShhZXMoeD1kYXRlX2FzZGF0ZSAsIHk9ZGVhdGhzX2xvZ195X2hhdF9wZXJjZW50X2NoYW5nZV95X2hhdCApLCBhbHBoYT0xLCBjb2xvcj0iYmxhY2siICApICsKICAgICAgICAgI2dlb21fc21vb3RoKCBhZXMoeD1kYXRlX2FzZGF0ZSAsIHk9ZGVhdGhzX2xvZ195X2hhdF9wZXJjZW50X2NoYW5nZSksIGFscGhhPS4zLCBzcGFuPS4wNSkgKyAjLCBzcGFuPS4wNQogICAgICAgICAjZ2VvbV9saW5lKCBhZXMoeD1kYXRlX2FzZGF0ZSwgeT1kZWF0aHNfbG9nX3lfaGF0LCBjb2xvcj1kYXRhc2V0LCBncm91cD1ncm91cCkpICsgIwogICAgICAgICAjZ2VvbV9saW5lKGRhdGE9dGVtcF9kZjIsIGFlcyh4PWRhdGVfYXNkYXRlLCB5PXlfaGF0X21lYW4pLCBjb2xvcj0iYmxhY2siLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSArCiAgICAgICAgIHRoZW1lX2J3KCkgKwogICAgICAgICBnZ3RpdGxlKCJVU0EgUTMwIERlYXRocyIpICsgeWxhYigiRGFpbHkgUGVyY2VudCBDaGFuZ2UgRGVhdGhzIikgIyArIGZhY2V0X3dyYXAofmRhdGFzZXQpCgojcDBhIC8gcDBiCgoKIyMjIyMKI0NoaW5hIFExNDgKCnRlc3QgPC0gbGhzX2xvbmdfY2xlYW5faW1wdXRlZCAlPiUgbXV0YXRlKGdyb3VwPXBhc3RlKGRhdGFzZXQsd2lraWRhdGFfaWQsZGVhdGhzX2xvZ19ncm91cF9udW1iZXIpKSAlPiUgZmlsdGVyKHdpa2lkYXRhX2lkPT0iUTE0OCIpICU+JSAKICAgICAgICBtdXRhdGUoZ3JvdXA9cGFzdGUoZGF0YXNldCwgd2lraWRhdGFfaWQsZGVhdGhzX2xvZ19ncm91cF9udW1iZXIpKSAlPiUKICAgICAgICBhcnJhbmdlKGRhdGVfYXNkYXRlKSAjJT4lCgpwMWEgPC0gdGVzdCAlPiUgCmdncGxvdCgpICsgCiAgIGdlb21fcG9pbnQoIGFlcyh4PWRhdGVfYXNkYXRlLCB5PWRlYXRoc19sb2csIGNvbG9yPWRhdGFzZXQpLCBhbHBoYT0uMykgKwogICBnZW9tX2xpbmUoIGFlcyh4PWRhdGVfYXNkYXRlLCB5PWRlYXRoc19sb2dfeV9oYXQsIGNvbG9yPWRhdGFzZXQsIGdyb3VwPWdyb3VwKSkgKyAjCiAgICNnZW9tX2xpbmUoZGF0YT10ZW1wX2RmMiwgYWVzKHg9ZGF0ZV9hc2RhdGUsIHk9eV9oYXRfbWVhbiksIGNvbG9yPSJibGFjayIsIGxpbmV0eXBlID0gImRhc2hlZCIpICsKICAgdGhlbWVfYncoKSArCiAgIGdndGl0bGUoIkNoaW5hIFExNDggRGVhdGhzIikKCnAxYiA8LSB0ZXN0ICU+JQogICAgICAgZ2dwbG90KCkgKyAKICAgICAgICAgZ2VvbV9wb2ludCggYWVzKHg9ZGF0ZV9hc2RhdGUgLCB5PWRlYXRoc19sb2dfeV9oYXRfcGVyY2VudF9jaGFuZ2UsIGNvbG9yPWRhdGFzZXQpLCBhbHBoYT0uMykgKwogICAgICAgICBnZW9tX2xpbmUoYWVzKHg9ZGF0ZV9hc2RhdGUgLCB5PWRlYXRoc19sb2dfeV9oYXRfcGVyY2VudF9jaGFuZ2VfeV9oYXQgKSwgYWxwaGE9MSwgY29sb3I9ImJsYWNrIikgKwogICAgICAgICAjZ2VvbV9zbW9vdGgoIGFlcyh4PWRhdGVfYXNkYXRlICwgeT1kZWF0aHNfbG9nX3lfaGF0X3BlcmNlbnRfY2hhbmdlKSwgYWxwaGE9LjMsIHNwYW49LjA1KSArICMsIHNwYW49LjA1CiAgICAgICAgICNnZW9tX2xpbmUoIGFlcyh4PWRhdGVfYXNkYXRlLCB5PWRlYXRoc19sb2dfeV9oYXQsIGNvbG9yPWRhdGFzZXQsIGdyb3VwPWdyb3VwKSkgKyAjCiAgICAgICAgICNnZW9tX2xpbmUoZGF0YT10ZW1wX2RmMiwgYWVzKHg9ZGF0ZV9hc2RhdGUsIHk9eV9oYXRfbWVhbiksIGNvbG9yPSJibGFjayIsIGxpbmV0eXBlID0gImRhc2hlZCIpICsKICAgICAgICAgdGhlbWVfYncoKSArCiAgIGdndGl0bGUoIkNoaW5hIFExNDggRGVhdGhzIikrIHlsYWIoIkRhaWx5IFBlcmNlbnQgQ2hhbmdlIERlYXRocyIpCiAgIAoKI3AxYSAvIHAxYgoKI0luZGlhCiMiUTY2OCIKCnRlc3QgPC0gbGhzX2xvbmdfY2xlYW5faW1wdXRlZCAlPiUgbXV0YXRlKGdyb3VwPXBhc3RlKGRhdGFzZXQsd2lraWRhdGFfaWQsZGVhdGhzX2xvZ195X2hhdF9wZXJjZW50X2NoYW5nZSkpICU+JSBmaWx0ZXIod2lraWRhdGFfaWQ9PSJRNjY4IikgJT4lIAogICAgICAgIG11dGF0ZShncm91cD1wYXN0ZShkYXRhc2V0LCB3aWtpZGF0YV9pZCxkZWF0aHNfbG9nX2dyb3VwX251bWJlcikpICU+JQogICAgICAgIGFycmFuZ2UoZGF0ZV9hc2RhdGUpICMlPiUKICAgICAgICAjbXV0YXRlKCBkZWF0aHNfbG9nX3lfaGF0X3BlcmNlbnRfY2hhbmdlID0gYnJlYWtwb2ludHMoZm9ybXVsYT1kZWF0aHNfbG9nX3lfaGF0X3BlcmNlbnRfY2hhbmdlIH4gMSwgZGF0YT0uICkgJT4lIGZpdHRlZC52YWx1ZXMoKSApCgoKcDJhIDwtIHRlc3QgJT4lCmdncGxvdCgpICsgCiAgIGdlb21fcG9pbnQoIGFlcyh4PWRhdGVfYXNkYXRlLCB5PWRlYXRoc19sb2csIGNvbG9yPWRhdGFzZXQpLCBhbHBoYT0uMykgKwogICBnZW9tX2xpbmUoIGFlcyh4PWRhdGVfYXNkYXRlLCB5PWRlYXRoc19sb2dfeV9oYXQsIGNvbG9yPWRhdGFzZXQsIGdyb3VwPWdyb3VwKSkgKyAjCiAgICNnZW9tX2xpbmUoZGF0YT10ZW1wX2RmMiwgYWVzKHg9ZGF0ZV9hc2RhdGUsIHk9eV9oYXRfbWVhbiksIGNvbG9yPSJibGFjayIsIGxpbmV0eXBlID0gImRhc2hlZCIpICsKICAgdGhlbWVfYncoKSArCiAgIGdndGl0bGUoIkluZGlhIFE2NjggRGVhdGhzIikKCnAyYiA8LSB0ZXN0ICU+JQogICAgICAgZ2dwbG90KCkgKyAKICAgICAgICAgZ2VvbV9wb2ludCggYWVzKHg9ZGF0ZV9hc2RhdGUgLCB5PWRlYXRoc19sb2dfeV9oYXRfcGVyY2VudF9jaGFuZ2UsIGNvbG9yPWRhdGFzZXQpLCBhbHBoYT0uMykgKwogICAgICAgICBnZW9tX2xpbmUoYWVzKHg9ZGF0ZV9hc2RhdGUgLCB5PWRlYXRoc19sb2dfeV9oYXRfcGVyY2VudF9jaGFuZ2VfeV9oYXQgKSwgYWxwaGE9MSwgY29sb3I9ImJsYWNrIikgKwogICAgICAgICAjZ2VvbV9zbW9vdGgoIGFlcyh4PWRhdGVfYXNkYXRlICwgeT1kZWF0aHNfbG9nX3lfaGF0X3BlcmNlbnRfY2hhbmdlKSwgYWxwaGE9LjMsIHNwYW49LjA1KSArICMsIHNwYW49LjA1CiAgICAgICAgICNnZW9tX2xpbmUoIGFlcyh4PWRhdGVfYXNkYXRlLCB5PWRlYXRoc19sb2dfeV9oYXQsIGNvbG9yPWRhdGFzZXQsIGdyb3VwPWdyb3VwKSkgKyAjCiAgICAgICAgICNnZW9tX2xpbmUoZGF0YT10ZW1wX2RmMiwgYWVzKHg9ZGF0ZV9hc2RhdGUsIHk9eV9oYXRfbWVhbiksIGNvbG9yPSJibGFjayIsIGxpbmV0eXBlID0gImRhc2hlZCIpICsKICAgICAgICAgdGhlbWVfYncoKSArCiAgIGdndGl0bGUoIkluZGlhIFE2NjggRGVhdGhzIikrIHlsYWIoIkRhaWx5IFBlcmNlbnQgQ2hhbmdlIERlYXRocyIpCiAKICAKI3AyYSAvIHAyYgoKI0JleGFyCiMiUTE2ODYxIgoKdGVzdCA8LSBsaHNfbG9uZ19jbGVhbl9pbXB1dGVkICU+JSBtdXRhdGUoZ3JvdXA9cGFzdGUoZGF0YXNldCx3aWtpZGF0YV9pZCxkZWF0aHNfbG9nX3lfaGF0X3BlcmNlbnRfY2hhbmdlKSkgJT4lIGZpbHRlcih3aWtpZGF0YV9pZD09IlExNjg2MSIpICU+JSAKICAgICAgICBtdXRhdGUoZ3JvdXA9cGFzdGUoZGF0YXNldCwgd2lraWRhdGFfaWQsZGVhdGhzX2xvZ19ncm91cF9udW1iZXIpKSAlPiUKICAgICAgICBhcnJhbmdlKGRhdGVfYXNkYXRlKSAjJT4lCiAgICAgICAgI211dGF0ZSggZGVhdGhzX2xvZ195X2hhdF9wZXJjZW50X2NoYW5nZSA9IGJyZWFrcG9pbnRzKGZvcm11bGE9ZGVhdGhzX2xvZ195X2hhdF9wZXJjZW50X2NoYW5nZSB+IDEsIGRhdGE9LiApICU+JSBmaXR0ZWQudmFsdWVzKCkgKQoKCnAzYSA8LSB0ZXN0ICU+JQogICAgICBnZ3Bsb3QoKSArIAogICAgICAgICBnZW9tX3BvaW50KCBhZXMoeD1kYXRlX2FzZGF0ZSwgeT1kZWF0aHNfbG9nLCBjb2xvcj1kYXRhc2V0KSwgYWxwaGE9LjMpICsKICAgICAgICAgZ2VvbV9saW5lKCBhZXMoeD1kYXRlX2FzZGF0ZSwgeT1kZWF0aHNfbG9nX3lfaGF0LCBjb2xvcj1kYXRhc2V0LCBncm91cD1ncm91cCkpICsgIwogICAgICAgICAjZ2VvbV9saW5lKGRhdGE9dGVtcF9kZjIsIGFlcyh4PWRhdGVfYXNkYXRlLCB5PXlfaGF0X21lYW4pLCBjb2xvcj0iYmxhY2siLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSArCiAgICAgICAgIHRoZW1lX2J3KCkgKwogICAgICAgICBnZ3RpdGxlKCJCZXhhciBDb3VudHkgUTE2ODYxIERlYXRocyIpCgpwM2IgPC0gdGVzdCAlPiUKICAgICAgIGdncGxvdCgpICsgCiAgICAgICAgIGdlb21fcG9pbnQoIGFlcyh4PWRhdGVfYXNkYXRlICwgeT1kZWF0aHNfbG9nX3lfaGF0X3BlcmNlbnRfY2hhbmdlLCBjb2xvcj1kYXRhc2V0KSwgYWxwaGE9LjMpICsKICAgICAgICAgZ2VvbV9saW5lKGFlcyh4PWRhdGVfYXNkYXRlICwgeT1kZWF0aHNfbG9nX3lfaGF0X3BlcmNlbnRfY2hhbmdlX3lfaGF0ICksIGFscGhhPTEsIGNvbG9yPSJibGFjayIpICsKICAgICAgICAgI2dlb21fc21vb3RoKCBhZXMoeD1kYXRlX2FzZGF0ZSAsIHk9ZGVhdGhzX2xvZ195X2hhdF9wZXJjZW50X2NoYW5nZSksIGFscGhhPS4zLCBzcGFuPS4wNSkgKyAjLCBzcGFuPS4wNQogICAgICAgICAjZ2VvbV9saW5lKCBhZXMoeD1kYXRlX2FzZGF0ZSwgeT1kZWF0aHNfbG9nX3lfaGF0LCBjb2xvcj1kYXRhc2V0LCBncm91cD1ncm91cCkpICsgIwogICAgICAgICAjZ2VvbV9saW5lKGRhdGE9dGVtcF9kZjIsIGFlcyh4PWRhdGVfYXNkYXRlLCB5PXlfaGF0X21lYW4pLCBjb2xvcj0iYmxhY2siLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSArCiAgICAgICAgIHRoZW1lX2J3KCkgKwogICBnZ3RpdGxlKCJCZXhhciBDb3VudHkgUTE2ODYxIERlYXRocyIpICsgeWxpbSgwLDEwMCkrIHlsYWIoIkRhaWx5IFBlcmNlbnQgQ2hhbmdlIERlYXRocyIpCiAgIAojcDNhIC8gcDNiCgoKCiNJdGFseQojIlEzOCIKCnRlc3QgPC0gbGhzX2xvbmdfY2xlYW5faW1wdXRlZCAlPiUgbXV0YXRlKGdyb3VwPXBhc3RlKGRhdGFzZXQsd2lraWRhdGFfaWQsZGVhdGhzX2xvZ195X2hhdF9wZXJjZW50X2NoYW5nZSkpICU+JSBmaWx0ZXIod2lraWRhdGFfaWQ9PSJRMzgiKSAlPiUgCiAgICAgICAgbXV0YXRlKGdyb3VwPXBhc3RlKGRhdGFzZXQsIHdpa2lkYXRhX2lkLGRlYXRoc19sb2dfZ3JvdXBfbnVtYmVyKSkgJT4lCiAgICAgICAgYXJyYW5nZShkYXRlX2FzZGF0ZSkgIyU+JQogICAgICAgICNtdXRhdGUoIGRlYXRoc19sb2dfeV9oYXRfcGVyY2VudF9jaGFuZ2UgPSBicmVha3BvaW50cyhmb3JtdWxhPWRlYXRoc19sb2dfeV9oYXRfcGVyY2VudF9jaGFuZ2UgfiAxLCBkYXRhPS4gKSAlPiUgZml0dGVkLnZhbHVlcygpICkKCgpwNGEgPC0gdGVzdCAlPiUKZ2dwbG90KCkgKyAKICAgZ2VvbV9wb2ludCggYWVzKHg9ZGF0ZV9hc2RhdGUsIHk9ZGVhdGhzX2xvZywgY29sb3I9ZGF0YXNldCksIGFscGhhPS4zKSArCiAgIGdlb21fbGluZSggYWVzKHg9ZGF0ZV9hc2RhdGUsIHk9ZGVhdGhzX2xvZ195X2hhdCwgY29sb3I9ZGF0YXNldCwgZ3JvdXA9Z3JvdXApKSArICMKICAgI2dlb21fbGluZShkYXRhPXRlbXBfZGYyLCBhZXMoeD1kYXRlX2FzZGF0ZSwgeT15X2hhdF9tZWFuKSwgY29sb3I9ImJsYWNrIiwgbGluZXR5cGUgPSAiZGFzaGVkIikgKwogICB0aGVtZV9idygpICsKICAgZ2d0aXRsZSgiSXRhbHkgUTM4IERlYXRocyIpCgpwNGIgPC0gdGVzdCAlPiUKICAgICAgIGdncGxvdCgpICsgCiAgICAgICAgIGdlb21fcG9pbnQoIGFlcyh4PWRhdGVfYXNkYXRlICwgeT1kZWF0aHNfbG9nX3lfaGF0X3BlcmNlbnRfY2hhbmdlLCBjb2xvcj1kYXRhc2V0KSwgYWxwaGE9LjMpICsKICAgICAgICAgZ2VvbV9saW5lKGFlcyh4PWRhdGVfYXNkYXRlICwgeT1kZWF0aHNfbG9nX3lfaGF0X3BlcmNlbnRfY2hhbmdlX3lfaGF0ICksIGFscGhhPTEsIGNvbG9yPSJibGFjayIpICsKICAgICAgICAgI2dlb21fc21vb3RoKCBhZXMoeD1kYXRlX2FzZGF0ZSAsIHk9ZGVhdGhzX2xvZ195X2hhdF9wZXJjZW50X2NoYW5nZSksIGFscGhhPS4zLCBzcGFuPS4wNSkgKyAjLCBzcGFuPS4wNQogICAgICAgICAjZ2VvbV9saW5lKCBhZXMoeD1kYXRlX2FzZGF0ZSwgeT1kZWF0aHNfbG9nX3lfaGF0LCBjb2xvcj1kYXRhc2V0LCBncm91cD1ncm91cCkpICsgIwogICAgICAgICAjZ2VvbV9saW5lKGRhdGE9dGVtcF9kZjIsIGFlcyh4PWRhdGVfYXNkYXRlLCB5PXlfaGF0X21lYW4pLCBjb2xvcj0iYmxhY2siLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSArCiAgICAgICAgIHRoZW1lX2J3KCkgKwogICBnZ3RpdGxlKCJJdGFseSBRMzggRGVhdGhzIikrIHlsYWIoIkRhaWx5IFBlcmNlbnQgQ2hhbmdlIERlYXRocyIpCiAgIAogICAgCiNwNGEgLyBwNGIKCgoKI1NvdXRoIEtvcmVhCiMiUTg4NCIKCnRlc3QgPC0gbGhzX2xvbmdfY2xlYW5faW1wdXRlZCAlPiUgbXV0YXRlKGdyb3VwPXBhc3RlKGRhdGFzZXQsd2lraWRhdGFfaWQsZGVhdGhzX2xvZ195X2hhdF9wZXJjZW50X2NoYW5nZSkpICU+JSBmaWx0ZXIod2lraWRhdGFfaWQ9PSJRODg0IikgJT4lIAogICAgICAgIG11dGF0ZShncm91cD1wYXN0ZShkYXRhc2V0LCB3aWtpZGF0YV9pZCxkZWF0aHNfbG9nX2dyb3VwX251bWJlcikpICU+JQogICAgICAgIGFycmFuZ2UoZGF0ZV9hc2RhdGUpICMlPiUKICAgICAgICAjbXV0YXRlKCBkZWF0aHNfbG9nX3lfaGF0X3BlcmNlbnRfY2hhbmdlID0gYnJlYWtwb2ludHMoZm9ybXVsYT1kZWF0aHNfbG9nX3lfaGF0X3BlcmNlbnRfY2hhbmdlIH4gMSwgZGF0YT0uICkgJT4lIGZpdHRlZC52YWx1ZXMoKSApCgoKcDVhIDwtIHRlc3QgJT4lCmdncGxvdCgpICsgCiAgIGdlb21fcG9pbnQoIGFlcyh4PWRhdGVfYXNkYXRlLCB5PWRlYXRoc19sb2csIGNvbG9yPWRhdGFzZXQpLCBhbHBoYT0uMykgKwogICBnZW9tX2xpbmUoIGFlcyh4PWRhdGVfYXNkYXRlLCB5PWRlYXRoc19sb2dfeV9oYXQsIGNvbG9yPWRhdGFzZXQsIGdyb3VwPWdyb3VwKSkgKyAjCiAgICNnZW9tX2xpbmUoZGF0YT10ZW1wX2RmMiwgYWVzKHg9ZGF0ZV9hc2RhdGUsIHk9eV9oYXRfbWVhbiksIGNvbG9yPSJibGFjayIsIGxpbmV0eXBlID0gImRhc2hlZCIpICsKICAgdGhlbWVfYncoKSArCiAgIGdndGl0bGUoIlNvdXRoIEtvcmVhIFE4ODQgIERlYXRocyIpCgpwNWIgPC0gdGVzdCAlPiUKICAgICAgIGdncGxvdCgpICsgCiAgICAgICAgIGdlb21fcG9pbnQoIGFlcyh4PWRhdGVfYXNkYXRlICwgeT1kZWF0aHNfbG9nX3lfaGF0X3BlcmNlbnRfY2hhbmdlLCBjb2xvcj1kYXRhc2V0KSwgYWxwaGE9LjMpICsKICAgICAgICAgZ2VvbV9saW5lKGFlcyh4PWRhdGVfYXNkYXRlICwgeT1kZWF0aHNfbG9nX3lfaGF0X3BlcmNlbnRfY2hhbmdlX3lfaGF0ICksIGFscGhhPTEsIGNvbG9yPSJibGFjayIpICsKICAgICAgICAgI2dlb21fc21vb3RoKCBhZXMoeD1kYXRlX2FzZGF0ZSAsIHk9ZGVhdGhzX2xvZ195X2hhdF9wZXJjZW50X2NoYW5nZSksIGFscGhhPS4zLCBzcGFuPS4wNSkgKyAjLCBzcGFuPS4wNQogICAgICAgICAjZ2VvbV9saW5lKCBhZXMoeD1kYXRlX2FzZGF0ZSwgeT1kZWF0aHNfbG9nX3lfaGF0LCBjb2xvcj1kYXRhc2V0LCBncm91cD1ncm91cCkpICsgIwogICAgICAgICAjZ2VvbV9saW5lKGRhdGE9dGVtcF9kZjIsIGFlcyh4PWRhdGVfYXNkYXRlLCB5PXlfaGF0X21lYW4pLCBjb2xvcj0iYmxhY2siLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSArCiAgICAgICAgIHRoZW1lX2J3KCkgKwogICBnZ3RpdGxlKCJTb3V0aCBLb3JlYSBRODg0IERlYXRocyIpICsgeWxhYigiRGFpbHkgUGVyY2VudCBDaGFuZ2UgRGVhdGhzIikKICAgCiAgICAKI3A1YSAvIHA1YgpgYGAKCkkgbmVlZCB0byBmaXggdGhpcywgVVNBIGhhcyBhIGZyYWN0aW9uIG9mIGEgZGVhdGgKCk5vdGUgdGhlIGRpc2NvbnRpbnVpdHkgaW4gQ2hpbiB3aGVuIHRoZXkgYWRkZWQgdGhvc2UgMWsgZGVhdGhzIHRvIHRoZSB0b3RhbAoKSW5kaWEgZGVhdGhzIGlzIGJyb2tlbiwgd2Ugc2hvdWxkbid0IGJlIGludGVycG9sYXRpbmcgYSByYXRlIGJlZm9yZSB3ZSB0aGluayB0aGUgbnVtYmVyIGlzIGdyZWF0ZXIgdGhhbiAwCgpgYGB7ciwgZmlnLndpZHRoPTEyLCBmaWcuaGVpZ2h0PTYgLHdhcm5pbmc9RkFMU0UsbWVzc2FnZT1GQUxTRSxlcnJvcj1GQUxTRX0KKHAwYSArIHAxYSArIHAyYSApIC8gKHAwYiArIHAxYiArIHAyYiApCmBgYAoKYGBge3IsIGZpZy53aWR0aD0xMiwgZmlnLmhlaWdodD02ICx3YXJuaW5nPUZBTFNFLG1lc3NhZ2U9RkFMU0UsZXJyb3I9RkFMU0V9CihwM2EgKyBwNGEgKyBwNWEpIC8gKHAzYiArIHA0YiArIHA1YikKYGBgCgoKCiMjIFBsb3QgVGVzdGluZyBDdXJ2ZXMgZm9yIFNlbGVjdCBMb2NhdGlvbnMKClNob3cgaG93IGludGVycG9sYXRpb24gd29ya3Mgb24gdGVzdGVkCgpVUyBpcyBhbiBleGFtcGxlIHdoZXJlIHdlIGludGVycG9sYXRlZCBwYXN0IG91ciBhdmFpbGFibGUgZGF0YS4gU2hvdWxkbid0IGRvIHRoYXQgZWl0aGVyIQpgYGB7ciwgZmlnLndpZHRoPTE2LCBmaWcuaGVpZ2h0PTEyLHdhcm5pbmc9RkFMU0UsbWVzc2FnZT1GQUxTRSxlcnJvcj1GQUxTRSwgcmVzdWx0cz0naGlkZSd9Cgp0ZXN0IDwtIGxoc19sb25nX2NsZWFuX2ltcHV0ZWQgJT4lCiAgICAgICAgbXV0YXRlKGdyb3VwPXBhc3RlKGRhdGFzZXQsd2lraWRhdGFfaWQsdGVzdGVkX3Blb3BsZV9sb2dfZ3JvdXBfbnVtYmVyKSkgJT4lCiAgICAgICAgZmlsdGVyKHdpa2lkYXRhX2lkPT0iUTMwIikgJT4lIAogICAgICAgIGFycmFuZ2UoZGF0ZV9hc2RhdGUpICAlPiUKICAgICAgICBtdXRhdGUoZGF0ZV9hc251bWVyaWMgPSBkYXRlX2FzZGF0ZSAlPiUgYXMubnVtZXJpYygpICkKCnAwYSA8LSB0ZXN0ICU+JQogICAgICAgIGdncGxvdCgpICsgCiAgICAgICAgICAgZ2VvbV9wb2ludCggYWVzKHg9ZGF0ZV9hc2RhdGUsIHk9dGVzdGVkX3Blb3BsZV9sb2csIGNvbG9yPWRhdGFzZXQpLCBhbHBoYT0uMykgKwogICAgICAgICAgIGdlb21fbGluZSggYWVzKHg9ZGF0ZV9hc2RhdGUsIHk9dGVzdGVkX3Blb3BsZV9sb2dfeV9oYXQsIGNvbG9yPWRhdGFzZXQsIGdyb3VwPWdyb3VwKSkgKyAjCiAgICAgICAgICAgI2dlb21fbGluZShkYXRhPXRlbXBfZGYyLCBhZXMoeD1kYXRlX2FzZGF0ZSwgeT15X2hhdF9tZWFuKSwgY29sb3I9ImJsYWNrIiwgbGluZXR5cGUgPSAiZGFzaGVkIikgKwogICAgICAgICAgIHRoZW1lX2J3KCkgKwogICAgICAgICAgIGdndGl0bGUoIlVTQSBRMzAgVGVzdGVkIikgICMrIGZhY2V0X3dyYXAofmRhdGFzZXQpIAoKcDBiIDwtIHRlc3QgJT4lCiAgICAgICBnZ3Bsb3QoKSArIAogICAgICAgICBnZW9tX3BvaW50KCBhZXMoeD1kYXRlX2FzZGF0ZSAsIHk9dGVzdGVkX3Blb3BsZV9sb2dfeV9oYXRfcGVyY2VudF9jaGFuZ2UsIGNvbG9yPWRhdGFzZXQpLCBhbHBoYT0uMyApICsKICAgICAgICAgZ2VvbV9saW5lKGFlcyh4PWRhdGVfYXNkYXRlICwgeT10ZXN0ZWRfcGVvcGxlX2xvZ195X2hhdF9wZXJjZW50X2NoYW5nZV95X2hhdCApLCBhbHBoYT0xLCBjb2xvcj0iYmxhY2siICApICsKICAgICAgICAgI2dlb21fc21vb3RoKCBhZXMoeD1kYXRlX2FzZGF0ZSAsIHk9dGVzdGVkX3Blb3BsZV9sb2dfeV9oYXRfcGVyY2VudF9jaGFuZ2UpLCBhbHBoYT0uMywgc3Bhbj0uMDUpICsgIywgc3Bhbj0uMDUKICAgICAgICAgI2dlb21fbGluZSggYWVzKHg9ZGF0ZV9hc2RhdGUsIHk9dGVzdGVkX3Blb3BsZV9sb2dfeV9oYXQsIGNvbG9yPWRhdGFzZXQsIGdyb3VwPWdyb3VwKSkgKyAjCiAgICAgICAgICNnZW9tX2xpbmUoZGF0YT10ZW1wX2RmMiwgYWVzKHg9ZGF0ZV9hc2RhdGUsIHk9eV9oYXRfbWVhbiksIGNvbG9yPSJibGFjayIsIGxpbmV0eXBlID0gImRhc2hlZCIpICsKICAgICAgICAgdGhlbWVfYncoKSArCiAgICAgICAgIGdndGl0bGUoIlVTQSBRMzAgdGVzdGVkX3Blb3BsZSIpICsgeWxhYigiRGFpbHkgUGVyY2VudCBDaGFuZ2UgdGVzdGVkX3Blb3BsZSIpICMgKyBmYWNldF93cmFwKH5kYXRhc2V0KQoKI3AwYSAvIHAwYgoKCiMjIyMjCiNDaGluYSBRMTQ4Cgp0ZXN0IDwtIGxoc19sb25nX2NsZWFuX2ltcHV0ZWQgJT4lIG11dGF0ZShncm91cD1wYXN0ZShkYXRhc2V0LHdpa2lkYXRhX2lkLHRlc3RlZF9wZW9wbGVfbG9nX2dyb3VwX251bWJlcikpICU+JSBmaWx0ZXIod2lraWRhdGFfaWQ9PSJRMTQ4IikgJT4lIAogICAgICAgIG11dGF0ZShncm91cD1wYXN0ZShkYXRhc2V0LCB3aWtpZGF0YV9pZCx0ZXN0ZWRfcGVvcGxlX2xvZ19ncm91cF9udW1iZXIpKSAlPiUKICAgICAgICBhcnJhbmdlKGRhdGVfYXNkYXRlKSAjJT4lCgpwMWEgPC0gdGVzdCAlPiUgCmdncGxvdCgpICsgCiAgIGdlb21fcG9pbnQoIGFlcyh4PWRhdGVfYXNkYXRlLCB5PXRlc3RlZF9wZW9wbGVfbG9nLCBjb2xvcj1kYXRhc2V0KSwgYWxwaGE9LjMpICsKICAgZ2VvbV9saW5lKCBhZXMoeD1kYXRlX2FzZGF0ZSwgeT10ZXN0ZWRfcGVvcGxlX2xvZ195X2hhdCwgY29sb3I9ZGF0YXNldCwgZ3JvdXA9Z3JvdXApKSArICMKICAgI2dlb21fbGluZShkYXRhPXRlbXBfZGYyLCBhZXMoeD1kYXRlX2FzZGF0ZSwgeT15X2hhdF9tZWFuKSwgY29sb3I9ImJsYWNrIiwgbGluZXR5cGUgPSAiZGFzaGVkIikgKwogICB0aGVtZV9idygpICsKICAgZ2d0aXRsZSgiQ2hpbmEgUTE0OCB0ZXN0ZWRfcGVvcGxlIikKCnAxYiA8LSB0ZXN0ICU+JQogICAgICAgZ2dwbG90KCkgKyAKICAgICAgICAgZ2VvbV9wb2ludCggYWVzKHg9ZGF0ZV9hc2RhdGUgLCB5PXRlc3RlZF9wZW9wbGVfbG9nX3lfaGF0X3BlcmNlbnRfY2hhbmdlLCBjb2xvcj1kYXRhc2V0KSwgYWxwaGE9LjMpICsKICAgICAgICAgZ2VvbV9saW5lKGFlcyh4PWRhdGVfYXNkYXRlICwgeT10ZXN0ZWRfcGVvcGxlX2xvZ195X2hhdF9wZXJjZW50X2NoYW5nZV95X2hhdCApLCBhbHBoYT0xLCBjb2xvcj0iYmxhY2siKSArCiAgICAgICAgICNnZW9tX3Ntb290aCggYWVzKHg9ZGF0ZV9hc2RhdGUgLCB5PXRlc3RlZF9wZW9wbGVfbG9nX3lfaGF0X3BlcmNlbnRfY2hhbmdlKSwgYWxwaGE9LjMsIHNwYW49LjA1KSArICMsIHNwYW49LjA1CiAgICAgICAgICNnZW9tX2xpbmUoIGFlcyh4PWRhdGVfYXNkYXRlLCB5PXRlc3RlZF9wZW9wbGVfbG9nX3lfaGF0LCBjb2xvcj1kYXRhc2V0LCBncm91cD1ncm91cCkpICsgIwogICAgICAgICAjZ2VvbV9saW5lKGRhdGE9dGVtcF9kZjIsIGFlcyh4PWRhdGVfYXNkYXRlLCB5PXlfaGF0X21lYW4pLCBjb2xvcj0iYmxhY2siLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSArCiAgICAgICAgIHRoZW1lX2J3KCkgKwogICBnZ3RpdGxlKCJDaGluYSBRMTQ4IHRlc3RlZF9wZW9wbGUiKSsgeWxhYigiRGFpbHkgUGVyY2VudCBDaGFuZ2UgdGVzdGVkX3Blb3BsZSIpCiAgIAoKI3AxYSAvIHAxYgoKI0luZGlhCiMiUTY2OCIKCnRlc3QgPC0gbGhzX2xvbmdfY2xlYW5faW1wdXRlZCAlPiUgbXV0YXRlKGdyb3VwPXBhc3RlKGRhdGFzZXQsd2lraWRhdGFfaWQsdGVzdGVkX3Blb3BsZV9sb2dfeV9oYXRfcGVyY2VudF9jaGFuZ2UpKSAlPiUgZmlsdGVyKHdpa2lkYXRhX2lkPT0iUTY2OCIpICU+JSAKICAgICAgICBtdXRhdGUoZ3JvdXA9cGFzdGUoZGF0YXNldCwgd2lraWRhdGFfaWQsdGVzdGVkX3Blb3BsZV9sb2dfZ3JvdXBfbnVtYmVyKSkgJT4lCiAgICAgICAgYXJyYW5nZShkYXRlX2FzZGF0ZSkgIyU+JQogICAgICAgICNtdXRhdGUoIHRlc3RlZF9wZW9wbGVfbG9nX3lfaGF0X3BlcmNlbnRfY2hhbmdlID0gYnJlYWtwb2ludHMoZm9ybXVsYT10ZXN0ZWRfcGVvcGxlX2xvZ195X2hhdF9wZXJjZW50X2NoYW5nZSB+IDEsIGRhdGE9LiApICU+JSBmaXR0ZWQudmFsdWVzKCkgKQoKCnAyYSA8LSB0ZXN0ICU+JQpnZ3Bsb3QoKSArIAogICBnZW9tX3BvaW50KCBhZXMoeD1kYXRlX2FzZGF0ZSwgeT10ZXN0ZWRfcGVvcGxlX2xvZywgY29sb3I9ZGF0YXNldCksIGFscGhhPS4zKSArCiAgIGdlb21fbGluZSggYWVzKHg9ZGF0ZV9hc2RhdGUsIHk9dGVzdGVkX3Blb3BsZV9sb2dfeV9oYXQsIGNvbG9yPWRhdGFzZXQsIGdyb3VwPWdyb3VwKSkgKyAjCiAgICNnZW9tX2xpbmUoZGF0YT10ZW1wX2RmMiwgYWVzKHg9ZGF0ZV9hc2RhdGUsIHk9eV9oYXRfbWVhbiksIGNvbG9yPSJibGFjayIsIGxpbmV0eXBlID0gImRhc2hlZCIpICsKICAgdGhlbWVfYncoKSArCiAgIGdndGl0bGUoIkluZGlhIFE2NjggdGVzdGVkX3Blb3BsZSIpCgpwMmIgPC0gdGVzdCAlPiUKICAgICAgIGdncGxvdCgpICsgCiAgICAgICAgIGdlb21fcG9pbnQoIGFlcyh4PWRhdGVfYXNkYXRlICwgeT10ZXN0ZWRfcGVvcGxlX2xvZ195X2hhdF9wZXJjZW50X2NoYW5nZSwgY29sb3I9ZGF0YXNldCksIGFscGhhPS4zKSArCiAgICAgICAgIGdlb21fbGluZShhZXMoeD1kYXRlX2FzZGF0ZSAsIHk9dGVzdGVkX3Blb3BsZV9sb2dfeV9oYXRfcGVyY2VudF9jaGFuZ2VfeV9oYXQgKSwgYWxwaGE9MSwgY29sb3I9ImJsYWNrIikgKwogICAgICAgICAjZ2VvbV9zbW9vdGgoIGFlcyh4PWRhdGVfYXNkYXRlICwgeT10ZXN0ZWRfcGVvcGxlX2xvZ195X2hhdF9wZXJjZW50X2NoYW5nZSksIGFscGhhPS4zLCBzcGFuPS4wNSkgKyAjLCBzcGFuPS4wNQogICAgICAgICAjZ2VvbV9saW5lKCBhZXMoeD1kYXRlX2FzZGF0ZSwgeT10ZXN0ZWRfcGVvcGxlX2xvZ195X2hhdCwgY29sb3I9ZGF0YXNldCwgZ3JvdXA9Z3JvdXApKSArICMKICAgICAgICAgI2dlb21fbGluZShkYXRhPXRlbXBfZGYyLCBhZXMoeD1kYXRlX2FzZGF0ZSwgeT15X2hhdF9tZWFuKSwgY29sb3I9ImJsYWNrIiwgbGluZXR5cGUgPSAiZGFzaGVkIikgKwogICAgICAgICB0aGVtZV9idygpICsKICAgZ2d0aXRsZSgiSW5kaWEgUTY2OCB0ZXN0ZWRfcGVvcGxlIikrIHlsYWIoIkRhaWx5IFBlcmNlbnQgQ2hhbmdlIHRlc3RlZF9wZW9wbGUiKQogCiAgCiNwMmEgLyBwMmIKCiNCZXhhcgojIlExNjg2MSIKCnRlc3QgPC0gbGhzX2xvbmdfY2xlYW5faW1wdXRlZCAlPiUgbXV0YXRlKGdyb3VwPXBhc3RlKGRhdGFzZXQsd2lraWRhdGFfaWQsdGVzdGVkX3Blb3BsZV9sb2dfeV9oYXRfcGVyY2VudF9jaGFuZ2UpKSAlPiUgZmlsdGVyKHdpa2lkYXRhX2lkPT0iUTE2ODYxIikgJT4lIAogICAgICAgIG11dGF0ZShncm91cD1wYXN0ZShkYXRhc2V0LCB3aWtpZGF0YV9pZCx0ZXN0ZWRfcGVvcGxlX2xvZ19ncm91cF9udW1iZXIpKSAlPiUKICAgICAgICBhcnJhbmdlKGRhdGVfYXNkYXRlKSAjJT4lCiAgICAgICAgI211dGF0ZSggdGVzdGVkX3Blb3BsZV9sb2dfeV9oYXRfcGVyY2VudF9jaGFuZ2UgPSBicmVha3BvaW50cyhmb3JtdWxhPXRlc3RlZF9wZW9wbGVfbG9nX3lfaGF0X3BlcmNlbnRfY2hhbmdlIH4gMSwgZGF0YT0uICkgJT4lIGZpdHRlZC52YWx1ZXMoKSApCgoKcDNhIDwtIHRlc3QgJT4lCiAgICAgIGdncGxvdCgpICsgCiAgICAgICAgIGdlb21fcG9pbnQoIGFlcyh4PWRhdGVfYXNkYXRlLCB5PXRlc3RlZF9wZW9wbGVfbG9nLCBjb2xvcj1kYXRhc2V0KSwgYWxwaGE9LjMpICsKICAgICAgICAgZ2VvbV9saW5lKCBhZXMoeD1kYXRlX2FzZGF0ZSwgeT10ZXN0ZWRfcGVvcGxlX2xvZ195X2hhdCwgY29sb3I9ZGF0YXNldCwgZ3JvdXA9Z3JvdXApKSArICMKICAgICAgICAgI2dlb21fbGluZShkYXRhPXRlbXBfZGYyLCBhZXMoeD1kYXRlX2FzZGF0ZSwgeT15X2hhdF9tZWFuKSwgY29sb3I9ImJsYWNrIiwgbGluZXR5cGUgPSAiZGFzaGVkIikgKwogICAgICAgICB0aGVtZV9idygpICsKICAgICAgICAgZ2d0aXRsZSgiQmV4YXIgQ291bnR5IFExNjg2MSB0ZXN0ZWRfcGVvcGxlIikKCnAzYiA8LSB0ZXN0ICU+JQogICAgICAgZ2dwbG90KCkgKyAKICAgICAgICAgZ2VvbV9wb2ludCggYWVzKHg9ZGF0ZV9hc2RhdGUgLCB5PXRlc3RlZF9wZW9wbGVfbG9nX3lfaGF0X3BlcmNlbnRfY2hhbmdlLCBjb2xvcj1kYXRhc2V0KSwgYWxwaGE9LjMpICsKICAgICAgICAgZ2VvbV9saW5lKGFlcyh4PWRhdGVfYXNkYXRlICwgeT10ZXN0ZWRfcGVvcGxlX2xvZ195X2hhdF9wZXJjZW50X2NoYW5nZV95X2hhdCApLCBhbHBoYT0xLCBjb2xvcj0iYmxhY2siKSArCiAgICAgICAgICNnZW9tX3Ntb290aCggYWVzKHg9ZGF0ZV9hc2RhdGUgLCB5PXRlc3RlZF9wZW9wbGVfbG9nX3lfaGF0X3BlcmNlbnRfY2hhbmdlKSwgYWxwaGE9LjMsIHNwYW49LjA1KSArICMsIHNwYW49LjA1CiAgICAgICAgICNnZW9tX2xpbmUoIGFlcyh4PWRhdGVfYXNkYXRlLCB5PXRlc3RlZF9wZW9wbGVfbG9nX3lfaGF0LCBjb2xvcj1kYXRhc2V0LCBncm91cD1ncm91cCkpICsgIwogICAgICAgICAjZ2VvbV9saW5lKGRhdGE9dGVtcF9kZjIsIGFlcyh4PWRhdGVfYXNkYXRlLCB5PXlfaGF0X21lYW4pLCBjb2xvcj0iYmxhY2siLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSArCiAgICAgICAgIHRoZW1lX2J3KCkgKwogICBnZ3RpdGxlKCJCZXhhciBDb3VudHkgUTE2ODYxIHRlc3RlZF9wZW9wbGUiKSArIHlsaW0oMCwxMDApKyB5bGFiKCJEYWlseSBQZXJjZW50IENoYW5nZSB0ZXN0ZWRfcGVvcGxlIikKICAgCiNwM2EgLyBwM2IKCgoKI0l0YWx5CiMiUTM4IgoKdGVzdCA8LSBsaHNfbG9uZ19jbGVhbl9pbXB1dGVkICU+JSBtdXRhdGUoZ3JvdXA9cGFzdGUoZGF0YXNldCx3aWtpZGF0YV9pZCx0ZXN0ZWRfcGVvcGxlX2xvZ195X2hhdF9wZXJjZW50X2NoYW5nZSkpICU+JSBmaWx0ZXIod2lraWRhdGFfaWQ9PSJRMzgiKSAlPiUgCiAgICAgICAgbXV0YXRlKGdyb3VwPXBhc3RlKGRhdGFzZXQsIHdpa2lkYXRhX2lkLHRlc3RlZF9wZW9wbGVfbG9nX2dyb3VwX251bWJlcikpICU+JQogICAgICAgIGFycmFuZ2UoZGF0ZV9hc2RhdGUpICMlPiUKICAgICAgICAjbXV0YXRlKCB0ZXN0ZWRfcGVvcGxlX2xvZ195X2hhdF9wZXJjZW50X2NoYW5nZSA9IGJyZWFrcG9pbnRzKGZvcm11bGE9dGVzdGVkX3Blb3BsZV9sb2dfeV9oYXRfcGVyY2VudF9jaGFuZ2UgfiAxLCBkYXRhPS4gKSAlPiUgZml0dGVkLnZhbHVlcygpICkKCgpwNGEgPC0gdGVzdCAlPiUKZ2dwbG90KCkgKyAKICAgZ2VvbV9wb2ludCggYWVzKHg9ZGF0ZV9hc2RhdGUsIHk9dGVzdGVkX3Blb3BsZV9sb2csIGNvbG9yPWRhdGFzZXQpLCBhbHBoYT0uMykgKwogICBnZW9tX2xpbmUoIGFlcyh4PWRhdGVfYXNkYXRlLCB5PXRlc3RlZF9wZW9wbGVfbG9nX3lfaGF0LCBjb2xvcj1kYXRhc2V0LCBncm91cD1ncm91cCkpICsgIwogICAjZ2VvbV9saW5lKGRhdGE9dGVtcF9kZjIsIGFlcyh4PWRhdGVfYXNkYXRlLCB5PXlfaGF0X21lYW4pLCBjb2xvcj0iYmxhY2siLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSArCiAgIHRoZW1lX2J3KCkgKwogICBnZ3RpdGxlKCJJdGFseSBRMzggdGVzdGVkX3Blb3BsZSIpCgpwNGIgPC0gdGVzdCAlPiUKICAgICAgIGdncGxvdCgpICsgCiAgICAgICAgIGdlb21fcG9pbnQoIGFlcyh4PWRhdGVfYXNkYXRlICwgeT10ZXN0ZWRfcGVvcGxlX2xvZ195X2hhdF9wZXJjZW50X2NoYW5nZSwgY29sb3I9ZGF0YXNldCksIGFscGhhPS4zKSArCiAgICAgICAgIGdlb21fbGluZShhZXMoeD1kYXRlX2FzZGF0ZSAsIHk9dGVzdGVkX3Blb3BsZV9sb2dfeV9oYXRfcGVyY2VudF9jaGFuZ2VfeV9oYXQgKSwgYWxwaGE9MSwgY29sb3I9ImJsYWNrIikgKwogICAgICAgICAjZ2VvbV9zbW9vdGgoIGFlcyh4PWRhdGVfYXNkYXRlICwgeT10ZXN0ZWRfcGVvcGxlX2xvZ195X2hhdF9wZXJjZW50X2NoYW5nZSksIGFscGhhPS4zLCBzcGFuPS4wNSkgKyAjLCBzcGFuPS4wNQogICAgICAgICAjZ2VvbV9saW5lKCBhZXMoeD1kYXRlX2FzZGF0ZSwgeT10ZXN0ZWRfcGVvcGxlX2xvZ195X2hhdCwgY29sb3I9ZGF0YXNldCwgZ3JvdXA9Z3JvdXApKSArICMKICAgICAgICAgI2dlb21fbGluZShkYXRhPXRlbXBfZGYyLCBhZXMoeD1kYXRlX2FzZGF0ZSwgeT15X2hhdF9tZWFuKSwgY29sb3I9ImJsYWNrIiwgbGluZXR5cGUgPSAiZGFzaGVkIikgKwogICAgICAgICB0aGVtZV9idygpICsKICAgZ2d0aXRsZSgiSXRhbHkgUTM4IHRlc3RlZF9wZW9wbGUiKSsgeWxhYigiRGFpbHkgUGVyY2VudCBDaGFuZ2UgdGVzdGVkX3Blb3BsZSIpCiAgIAogICAgCiNwNGEgLyBwNGIKCgoKI1NvdXRoIEtvcmVhCiMiUTg4NCIKCnRlc3QgPC0gbGhzX2xvbmdfY2xlYW5faW1wdXRlZCAlPiUgbXV0YXRlKGdyb3VwPXBhc3RlKGRhdGFzZXQsd2lraWRhdGFfaWQsdGVzdGVkX3Blb3BsZV9sb2dfeV9oYXRfcGVyY2VudF9jaGFuZ2UpKSAlPiUgZmlsdGVyKHdpa2lkYXRhX2lkPT0iUTg4NCIpICU+JSAKICAgICAgICBtdXRhdGUoZ3JvdXA9cGFzdGUoZGF0YXNldCwgd2lraWRhdGFfaWQsdGVzdGVkX3Blb3BsZV9sb2dfZ3JvdXBfbnVtYmVyKSkgJT4lCiAgICAgICAgYXJyYW5nZShkYXRlX2FzZGF0ZSkgIyU+JQogICAgICAgICNtdXRhdGUoIHRlc3RlZF9wZW9wbGVfbG9nX3lfaGF0X3BlcmNlbnRfY2hhbmdlID0gYnJlYWtwb2ludHMoZm9ybXVsYT10ZXN0ZWRfcGVvcGxlX2xvZ195X2hhdF9wZXJjZW50X2NoYW5nZSB+IDEsIGRhdGE9LiApICU+JSBmaXR0ZWQudmFsdWVzKCkgKQoKCnA1YSA8LSB0ZXN0ICU+JQpnZ3Bsb3QoKSArIAogICBnZW9tX3BvaW50KCBhZXMoeD1kYXRlX2FzZGF0ZSwgeT10ZXN0ZWRfcGVvcGxlX2xvZywgY29sb3I9ZGF0YXNldCksIGFscGhhPS4zKSArCiAgIGdlb21fbGluZSggYWVzKHg9ZGF0ZV9hc2RhdGUsIHk9dGVzdGVkX3Blb3BsZV9sb2dfeV9oYXQsIGNvbG9yPWRhdGFzZXQsIGdyb3VwPWdyb3VwKSkgKyAjCiAgICNnZW9tX2xpbmUoZGF0YT10ZW1wX2RmMiwgYWVzKHg9ZGF0ZV9hc2RhdGUsIHk9eV9oYXRfbWVhbiksIGNvbG9yPSJibGFjayIsIGxpbmV0eXBlID0gImRhc2hlZCIpICsKICAgdGhlbWVfYncoKSArCiAgIGdndGl0bGUoIlNvdXRoIEtvcmVhIFE4ODQgIHRlc3RlZF9wZW9wbGUiKQoKcDViIDwtIHRlc3QgJT4lCiAgICAgICBnZ3Bsb3QoKSArIAogICAgICAgICBnZW9tX3BvaW50KCBhZXMoeD1kYXRlX2FzZGF0ZSAsIHk9dGVzdGVkX3Blb3BsZV9sb2dfeV9oYXRfcGVyY2VudF9jaGFuZ2UsIGNvbG9yPWRhdGFzZXQpLCBhbHBoYT0uMykgKwogICAgICAgICBnZW9tX2xpbmUoYWVzKHg9ZGF0ZV9hc2RhdGUgLCB5PXRlc3RlZF9wZW9wbGVfbG9nX3lfaGF0X3BlcmNlbnRfY2hhbmdlX3lfaGF0ICksIGFscGhhPTEsIGNvbG9yPSJibGFjayIpICsKICAgICAgICAgI2dlb21fc21vb3RoKCBhZXMoeD1kYXRlX2FzZGF0ZSAsIHk9dGVzdGVkX3Blb3BsZV9sb2dfeV9oYXRfcGVyY2VudF9jaGFuZ2UpLCBhbHBoYT0uMywgc3Bhbj0uMDUpICsgIywgc3Bhbj0uMDUKICAgICAgICAgI2dlb21fbGluZSggYWVzKHg9ZGF0ZV9hc2RhdGUsIHk9dGVzdGVkX3Blb3BsZV9sb2dfeV9oYXQsIGNvbG9yPWRhdGFzZXQsIGdyb3VwPWdyb3VwKSkgKyAjCiAgICAgICAgICNnZW9tX2xpbmUoZGF0YT10ZW1wX2RmMiwgYWVzKHg9ZGF0ZV9hc2RhdGUsIHk9eV9oYXRfbWVhbiksIGNvbG9yPSJibGFjayIsIGxpbmV0eXBlID0gImRhc2hlZCIpICsKICAgICAgICAgdGhlbWVfYncoKSArCiAgIGdndGl0bGUoIlNvdXRoIEtvcmVhIFE4ODQgdGVzdGVkX3Blb3BsZSIpICsgeWxhYigiRGFpbHkgUGVyY2VudCBDaGFuZ2UgdGVzdGVkX3Blb3BsZSIpCiAgIAogICAgCiNwNWEgLyBwNWIKYGBgCgoKTm90ZSB0aGF0IENoaW5hIGNvdW50cyBvZiB0ZXN0aW5nIGFyZSBhbG1vc3QgbmV2ZXIgZ2l2ZW4gYXQgdGhlIG5hdGlvbmFsIGxldmVsLiBXZSBoYXZlIHNvbWUgYnJva2VuIGRvd24gYnkgc3BlY2lmaWMgcHJvdmluY2VzIGJ1dCB0YWJsZXMgdXN1YWxseSBkb24ndCBoYXZlIGEgIkNoaW5hIiByb3cuCgpgYGB7ciwgZmlnLndpZHRoPTEyLCBmaWcuaGVpZ2h0PTYgLHdhcm5pbmc9RkFMU0UsbWVzc2FnZT1GQUxTRSxlcnJvcj1GQUxTRX0KKHAwYSArIHAxYSArIHAyYSApIC8gKHAwYiArIHAxYiArIHAyYiApCmBgYAoKYGBge3IsIGZpZy53aWR0aD0xMiwgZmlnLmhlaWdodD02ICx3YXJuaW5nPUZBTFNFLG1lc3NhZ2U9RkFMU0UsZXJyb3I9RkFMU0V9CihwM2EgKyBwNGEgKyBwNWEpIC8gKHAzYiArIHA0YiArIHA1YikKYGBgCgoKIyBBbGlnbmluZyBDdXJ2ZXMgYnkgVGFrZW9mZgoKYGBge3IsIGVjaG89RkFMU0Usd2FybmluZz1GQUxTRSxtZXNzYWdlPUZBTFNFLGVycm9yPUZBTFNFLCByZXN1bHRzPSdoaWRlJ30KCmxpYnJhcnkoZGF0YS50YWJsZSkKZ2VvbmFtZXMgPC0gZnJlYWQoIi9tZWRpYS9za3luZXQyLzkwNTg4NGYwLTc1NDYtNDI3My05MDYxLTEyYTc5MDgzMGJlYi9yd2RfZ2l0aHViX3ByaXZhdGUvTkVTU2NvdmlkMTkvZGF0YV90ZW1wL2FsbENvdW50cmllcy50eHQiLCBzZXA9Ilx0IikgJT4lIG11dGF0ZV9pZihpcy5udW1lcmljLGFzLmNoYXJhY3RlcikgJT4lIG11dGF0ZV9pZihpcy5mYWN0b3IsYXMuY2hhcmFjdGVyKQpkaW0oZ2VvbmFtZXMpICMxMiwwMDYsNDI2CgpnZW9uYW1lc19zbWFsbCA8LSBnZW9uYW1lcyAlPiUgZHBseXI6OnNlbGVjdChnZW9uYW1laWQ9VjEsIG5hbWVfdGV4dD1WMikgJT4lIGlubmVyX2pvaW4oIGxoc19sb25nX2NsZWFuX2ltcHV0ZWQgJT4lIGRwbHlyOjpzZWxlY3QoZ2VvbmFtZWlkKSAlPiUgZGlzdGluY3QoKSApCmRpbShnZW9uYW1lc19zbWFsbCkKCmRmX3Nsb3BlcyA8LSBsaHNfbG9uZ19jbGVhbl9pbXB1dGVkICU+JSAKICAgICAgICAgICAgIGdyb3VwX2J5KGdpZF9nZW9uYW1laWRfd2lraWRhdGFfaWQsIGdpZCwgZ2VvbmFtZWlkLCB3aWtpZGF0YV9pZCwgZGF0ZV9hc2RhdGUpICU+JSAKICAgICAgICAgICAgIHN1bW1hcmlzZSgKICAgICAgICAgICAgICAgICAgICBjb25maXJtZWQ9bWVkaWFuKGNvbmZpcm1lZCwgbmEucm09VCksCiAgICAgICAgICAgICAgICAgICAgZGVhdGhzPW1lZGlhbihkZWF0aHMsIG5hLnJtPVQpLAogICAgICAgICAgICAgICAgICAgIHRlc3RlZF9wZW9wbGU9bWVkaWFuKHRlc3RlZF9wZW9wbGUsIG5hLnJtPVQpLAogICAgICAgICAgICAgICAgICAgIHRlc3RlZF9zYW1wbGVzPW1lZGlhbih0ZXN0ZWRfc2FtcGxlcywgbmEucm09VCksCiAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgY29uZmlybWVkX2xvZ195X2hhdD1tZWRpYW4oY29uZmlybWVkX2xvZ195X2hhdCwgbmEucm09VCksCiAgICAgICAgICAgICAgICAgICAgZGVhdGhzX2xvZ195X2hhdD1tZWRpYW4oZGVhdGhzX2xvZ195X2hhdCwgbmEucm09VCksCiAgICAgICAgICAgICAgICAgICAgdGVzdGVkX3Blb3BsZV9sb2dfeV9oYXQ9bWVkaWFuKHRlc3RlZF9wZW9wbGVfbG9nX3lfaGF0LCBuYS5ybT1UKSwKCiAgICAgICAgICAgICAgICAgICAgY29uZmlybWVkX2xvZ195X2hhdF9wZXJjZW50X2NoYW5nZT1tZWRpYW4oY29uZmlybWVkX2xvZ195X2hhdF9wZXJjZW50X2NoYW5nZSwgbmEucm09VCksCiAgICAgICAgICAgICAgICAgICAgZGVhdGhzX2xvZ195X2hhdF9wZXJjZW50X2NoYW5nZT1tZWRpYW4oZGVhdGhzX2xvZ195X2hhdF9wZXJjZW50X2NoYW5nZSwgbmEucm09VCksCiAgICAgICAgICAgICAgICAgICAgdGVzdGVkX3Blb3BsZV9sb2dfeV9oYXRfcGVyY2VudF9jaGFuZ2U9bWVkaWFuKHRlc3RlZF9wZW9wbGVfbG9nX3lfaGF0X3BlcmNlbnRfY2hhbmdlLCBuYS5ybT1UKSwKCiAgICAgICAgICAgICAgICAgICAgY29uZmlybWVkX2xvZ195X2hhdF9wZXJjZW50X2NoYW5nZV95X2hhdD1tZWRpYW4oY29uZmlybWVkX2xvZ195X2hhdF9wZXJjZW50X2NoYW5nZV95X2hhdCwgbmEucm09VCksCiAgICAgICAgICAgICAgICAgICAgZGVhdGhzX2xvZ195X2hhdF9wZXJjZW50X2NoYW5nZV95X2hhdD1tZWRpYW4oZGVhdGhzX2xvZ195X2hhdF9wZXJjZW50X2NoYW5nZV95X2hhdCwgbmEucm09VCksCiAgICAgICAgICAgICAgICAgICAgdGVzdGVkX3Blb3BsZV9sb2dfeV9oYXRfcGVyY2VudF9jaGFuZ2VfeV9oYXQ9bWVkaWFuKHRlc3RlZF9wZW9wbGVfbG9nX3lfaGF0X3BlcmNlbnRfY2hhbmdlX3lfaGF0LCBuYS5ybT1UKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICN0ZXN0ZWRfc2FtcGxlc19sb2dfeV9oYXQ9bWVkaWFuKHRlc3RlZF9zYW1wbGVzX2xvZ195X2hhdCwgbmEucm09VCksICNoYXZlbid0IHdyaXR0ZW4gdGhlIGludGVycCBmb3IgdGhpcyB5ZXQKICAgICAgICAgICAgICAgICAgICApICU+JQogICAgICAgICAgICAgI3VuZ3JvdXAoKSAlPiUKICAgICAgICAgICAgIGxlZnRfam9pbihnZW9uYW1lc19zbWFsbCkgJT4lCiAgICAgICAgICAgICBncm91cF9ieShnaWRfZ2VvbmFtZWlkX3dpa2lkYXRhX2lkKSAlPiUgCiAgICAgICAgICAgICBhcnJhbmdlKGRhdGVfYXNkYXRlKSAlPiUgCiAgICAgICAgICAgICBtdXRhdGUodCA9IHJvd19udW1iZXIoKSkgJT4lCiAgICAgICAgICAgICBtdXRhdGUoY29uZmlybWVkX2xvZ195X2hhdF9wZXJjZW50X2NoYW5nZV95X2hhdF9mZD10c2liYmxlOjpkaWZmZXJlbmNlKGNvbmZpcm1lZF9sb2dfeV9oYXRfcGVyY2VudF9jaGFuZ2VfeV9oYXQpKSAlPiUKICAKICAgICAgICAgICAgICNTbyB0aGVyZSBhcmUgb25lcyB0aGF0IHN0YXJ0IGxvdyBhbmQgYnVpbGQgdXAKICAgICAgICAgICAgIG11dGF0ZSh0X2FsbGlnbmVkX21heGZkID0gIGNvbmZpcm1lZF9sb2dfeV9oYXRfcGVyY2VudF9jaGFuZ2VfeV9oYXRfZmQ9PW1heChjb25maXJtZWRfbG9nX3lfaGF0X3BlcmNlbnRfY2hhbmdlX3lfaGF0X2ZkLG5hLnJtPVQpICkgJT4lIAogICAgICAgICAgICAgI2J1dCB0aGVyZSBhcmUgb3RoZXIgb25lcyB0aGF0IGdvIGZyb20gemVybyB0byBoaWdoIGFuZCB0aG9zZSBhcmVuJ3QgZ2V0dGluZyBjYXVnaHQgYnkgdGhlIHRvcCBhYm92ZQogICAgICAgICAgICAgbXV0YXRlKHRfYWxsaWduZWRfbWF4X2F0XzAgPSAgY29uZmlybWVkX2xvZ195X2hhdF9wZXJjZW50X2NoYW5nZV95X2hhdD09bWF4KGNvbmZpcm1lZF9sb2dfeV9oYXRfcGVyY2VudF9jaGFuZ2VfeV9oYXQsbmEucm09VCkgJiB0PT0xICkgJT4lIAoKICAgICAgICAgICAgIG11dGF0ZSh0X2FsbGlnbmVkID0gaWZlbHNlKHRfYWxsaWduZWRfbWF4X2F0XzAgfCAodF9hbGxpZ25lZF9tYXhmZCAmIG1heCh0X2FsbGlnbmVkX21heF9hdF8wLCBuYS5ybT1UKT09RikgLCB0LCBOQSkgKSAlPiUgCiAgICAgICAgICAgICBtdXRhdGUodF9hbGxpZ25lZCA9IG1heCh0X2FsbGlnbmVkLCBuYS5ybT1UKSApICU+JQogICAgICAgICAgICAgbXV0YXRlKHRfYWxsaWduZWQgPSB0LW1heCh0X2FsbGlnbmVkLCBuYS5ybT1UKSApICU+JQoKICAgICAgICAgICAgIG11dGF0ZSh0X2FsbGlnbmVkX2ZpcnN0Y29uZmlybWVkID0gaWZlbHNlKGNvbmZpcm1lZD09bWluKGNvbmZpcm1lZCwgbmEucm09VCkgLCB0LCBOQSkgKSAlPiUgCiAgICAgICAgICAgICBtdXRhdGUodF9hbGxpZ25lZF9maXJzdGNvbmZpcm1lZCA9IG1heCh0X2FsbGlnbmVkX2ZpcnN0Y29uZmlybWVkLCBuYS5ybT1UKSApICU+JQogICAgICAgICAgICAgbXV0YXRlKHRfYWxsaWduZWRfZmlyc3Rjb25maXJtZWQgPSB0LW1heCh0X2FsbGlnbmVkX2ZpcnN0Y29uZmlybWVkLCBuYS5ybT1UKSApICU+JQoKICAgICAgICAgICAgICN0aGlzIHRocm93cyBhIGJ1bmNoIG9mIGluZmluaXRlIG1pc3NpbmcgYmVjYXVzZSBvZiBjb3VudHJpZXMgdGhhdCBoYXZlbid0IHlldCBoaXQgMTAwCiAgICAgICAgICAgICAjbXV0YXRlKHRfYWxsaWduZWRfMTAwY29uZmlybWVkXzEwMCA9IGlmZWxzZShjb25maXJtZWQ+PTEwMCAgLCB0LCBOQSkgKSAlPiUgCiAgICAgICAgICAgICAjbXV0YXRlKHRfYWxsaWduZWRfMTAwY29uZmlybWVkXzEwMCA9IGlmZWxzZSh0X2FsbGlnbmVkXzEwMGNvbmZpcm1lZF8xMDA9PW1pbih0X2FsbGlnbmVkXzEwMGNvbmZpcm1lZF8xMDAsIG5hLnJtPVQpICwgdCwgTkEpICkgJT4lIAogICAgICAgICAgICAgI211dGF0ZSh0X2FsbGlnbmVkXzEwMGNvbmZpcm1lZCA9IHQtbWF4KHRfYWxsaWduZWRfMTAwY29uZmlybWVkXzEwMCwgbmEucm09VCkgKSAlPiUKICAgICAgICAgICAgICNkcGx5cjo6c2VsZWN0KC10X2FsbGlnbmVkXzEwMGNvbmZpcm1lZF8xMDApICU+JQogICAgICAgICAgICAgdW5ncm91cCgpCmBgYAoKYGBge3IsIGV2YWw9Rn0KCmxpYnJhcnkoaW5mb3RoZW8pCiNPbmNlIHdlIHJlbW92ZWQgdGhlIG5vIHZhcmlhbmNlIHBsYWNlcyBteSBhbGlnbm1lbnQgaGFzIG1vcmUgbXV0dWFsIGluZm9ybWF0aW9uIHRoYW4gZWl0aGVyIGZpcnN0IGNvbmZpcm1lZCBvciAxMDAgY29uZmlybWVkCm11dGluZm9ybWF0aW9uKFg9ZGZfc2xvcGVzICU+JSBkcGx5cjo6c2VsZWN0KHQsdF9hbGxpZ25lZCx0X2FsbGlnbmVkX2ZpcnN0Y29uZmlybWVkLGNvbmZpcm1lZF9sb2dfeV9oYXRfcGVyY2VudF9jaGFuZ2VfeV9oYXQpICU+JSBkaXNjcmV0aXplKCksIG1ldGhvZD0iZW1wIikgI3dlIG91dHBlcmZvcm1lZCB0X2FsbGlnbmVkXzEwMGNvbmZpcm1lZCBidXQgaXQgd2Fzbid0IGF2YWlsIGZvciBtb3N0CgojZGZfc2xvcGVzICU+JSBmaWx0ZXIoYWJzKHRfYWxsaWduZWQpPDIwLGFicyh0X2FsbGlnbmVkXzEwMGNvbmZpcm1lZF8xMDApPDIwKSAlPiUgamFuaXRvcjo6dGFieWwodF9hbGxpZ25lZCwgdF9hbGxpZ25lZF8xMDBjb25maXJtZWRfMTAwKQojaGlzdChkZl9zbG9wZXMkdF9hbGxpZ25lZCAtIGRmX3Nsb3BlcyR0X2FsbGlnbmVkXzEwMGNvbmZpcm1lZF8xMDAsIGJyZWFrcz01MCkKICAKYGBgCgpQbG90IG9mIGN1cnZlcyByYXcgYW5kIHRoZW4gY3VydmVzIGFsbGlnbmVkIGJ5IHRha2VvZmYgc3RhcnQKCmBgYHtyLCBmaWcud2lkdGg9MTIsIGZpZy5oZWlnaHQ9MTIsIGVjaG89RkFMU0Usd2FybmluZz1GQUxTRSxtZXNzYWdlPUZBTFNFLGVycm9yPUZBTFNFLCByZXN1bHRzPSdoaWRlJ30KCiNkZl9zbG9wZXMgJT4lIG11dGF0ZShncm91cD1wYXN0ZSh3aWtpZGF0YV9pZCkpICU+JQojICAgICAgICAgICAgICBnZ3Bsb3QoKSArIAojICAgICAgICAgICAgICBnZW9tX2xpbmUoIGFlcyh4PXRfYWxsaWduZWQgLCB5PWNvbmZpcm1lZF9sb2dfeV9oYXRfcGVyY2VudF9jaGFuZ2VfeV9oYXQsIGdyb3VwPXdpa2lkYXRhX2lkKSwgYWxwaGE9LjA1LCBjb2xvcj0iYmx1ZSIpICsKIyAgICAgICAgICAgICAgdGhlbWVfYncoKSArCiMgICAgICAgICAgICAgIGdndGl0bGUoIkludGVycG9sYXRlZCBsb2cgY291bnQgYnkgQWxsaWduZWQgVCIpICsgeWxpbSgwLDEwMCkKCgpwX3RfYWxsaWduZWRfZmlyc3Rjb25maXJtZWQgPC0gIGRmX3Nsb3BlcyAlPiUgbXV0YXRlKGdyb3VwPXBhc3RlKHdpa2lkYXRhX2lkKSkgJT4lIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2dwbG90KCkgKyAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdlb21fbGluZSggYWVzKHg9dF9hbGxpZ25lZF9maXJzdGNvbmZpcm1lZCAsIHk9Y29uZmlybWVkX2xvZ195X2hhdF9wZXJjZW50X2NoYW5nZV95X2hhdCwgZ3JvdXA9Z3JvdXAsIGNvbG9yPXdpa2lkYXRhX2lkKSwgYWxwaGE9MSkgKwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhlbWVfYncoKSArCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZ3RpdGxlKCJJbnRlcnBvbGF0ZWQgbG9nIGNvdW50IGJ5IFQiKSArIHlsaW0oMCwxMDApICsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdnaGlnaGxpZ2h0KHdpa2lkYXRhX2lkICVpbiUgYygnUTMwJywnUTE0MzknLCdRNjY4JywnUTg4NCcsJ1ExNjg2MScsJ1ExNTknLCdRMzgnKSwgdW5oaWdobGlnaHRlZF9wYXJhbXM9bGlzdChhbHBoYT0uMSkpICsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2VvbV9zbW9vdGgoIGFlcyh4PXRfYWxsaWduZWRfZmlyc3Rjb25maXJtZWQgLCB5PWNvbmZpcm1lZF9sb2dfeV9oYXRfcGVyY2VudF9jaGFuZ2VfeV9oYXQpLCBzcGFuID0gMC4wNSkgICsgeGxpbSgtNTAsMTAwKQoKI3BfdF9hbGxpZ25lZF9maXJzdGNvbmZpcm1lZAoKCnBfdF9hbGxpZ25lZCA8LSBkZl9zbG9wZXMgJT4lIG11dGF0ZShncm91cD1wYXN0ZSh3aWtpZGF0YV9pZCkpICU+JSAKICAgICAgICAgICAgICAgZ2dwbG90KCkgKyAKICAgICAgICAgICAgICAgZ2VvbV9saW5lKCBhZXMoeD10X2FsbGlnbmVkICwgeT1jb25maXJtZWRfbG9nX3lfaGF0X3BlcmNlbnRfY2hhbmdlX3lfaGF0LCBncm91cD1ncm91cCwgY29sb3I9d2lraWRhdGFfaWQpLCBhbHBoYT0xKSArCiAgICAgICAgICAgICAgIHRoZW1lX2J3KCkgKwogICAgICAgICAgICAgICBnZ3RpdGxlKCJJbnRlcnBvbGF0ZWQgbG9nIGNvdW50IGJ5IEFsbGlnbmVkIFQiKSArIHlsaW0oMCwxMDApICsKICAgICAgICAgICAgICAgZ2doaWdobGlnaHQod2lraWRhdGFfaWQgJWluJSBjKCdRMzAnLCdRMTQzOScsJ1E2NjgnLCdRODg0JywnUTE2ODYxJywnUTE1OScsJ1EzOCcpLCB1bmhpZ2hsaWdodGVkX3BhcmFtcz1saXN0KGFscGhhPS4xKSkgKwogICAgICAgICAgICAgICBnZW9tX3Ntb290aCggYWVzKHg9dF9hbGxpZ25lZCAsIHk9Y29uZmlybWVkX2xvZ195X2hhdF9wZXJjZW50X2NoYW5nZV95X2hhdCksIHNwYW4gPSAwLjA1KSArIHhsaW0oLTUwLDEwMCkKCiNwX3RfYWxsaWduZWQKI2RmX3Nsb3BlcyAlPiUgbXV0YXRlKGdyb3VwPXBhc3RlKHdpa2lkYXRhX2lkKSkgJT4lIAojZ2dwbG90KCkgKyAKIyAgIGdlb21fbGluZSggYWVzKHg9dF9hbGxpZ25lZCAsIHk9Y29uZmlybWVkX2xvZ195X2hhdF9wZXJjZW50X2NoYW5nZV95X2hhdCwgZ3JvdXA9Z3JvdXAsIGNvbG9yPXdpa2lkYXRhX2lkKSwgYWxwaGE9MSkgKwojICAgdGhlbWVfYncoKSArCiMgICBnZ3RpdGxlKCJJbnRlcnBvbGF0ZWQgbG9nIGNvdW50IGJ5IEFsbGlnbmVkIFQiKSArIHlsaW0oMCwxMDApICArIHhsaW0oMCwxMDApICsKIyAgIGdnaGlnaGxpZ2h0KHdpa2lkYXRhX2lkICVpbiUgYygnUTMwJywnUTE0MzknLCdRNjY4JywnUTg4NCcsJ1ExNjg2MScsJ1ExNTknLCdRMzgnKSwgdW5oaWdobGlnaHRlZF9wYXJhbXM9bGlzdChhbHBoYT0uMSkpICsKIyAgIGdlb21fc21vb3RoKCBhZXMoeD10X2FsbGlnbmVkICwgeT1jb25maXJtZWRfbG9nX3lfaGF0X3BlcmNlbnRfY2hhbmdlX3lfaGF0KSwgc3BhbiA9IDAuMDUpIAoKCgpgYGAKClRoZSBpZGVhIGhlcmUgaXMgdGhhdCBjb21wbGV0ZWx5IHVuY29uc3RyYWluZWQsIENPVklELTE5IGdyb3d0aCBzaG91bGQgZm9sbG93IGEgbG9naXN0aWMgY3VydmUsIGZsYXQsIHVwc3dpbmcsIGNvbnN0YW50IGdyb3d0aCwgZG93bnN3aW5nLCBhbmQgZmxhdCBhZ2Fpbi4gVGhlIGFzc3VtcHRpb24gb2Ygbm8gdW5jb25zdHJhaW5lZCBncm93dGggbm8gbG9uZ2VyIGhvbGRzIGJlY2F1c2UgdGhlIHdvcmxkIGlzIHJlYWN0aW5nLCBidXQgdGhlcmUncyBzdGlsbCBhIHByZXR0eSB1bmlmb3JtbHkgY2hhcmFjdGVyaXN0aWMgdXBzd2luZyBhY3Jvc3MgZ2VvZ3JhcGhpYyB1bml0cy4gV2UgbG9vayBmb3IgdGhpcyBzaWduYWwgb2YgdGhlIGxhcmdlc3QgZmlyc3QgZGlmZmVyZW5jZSBpbiB0aGUgZGFpbHkgcGVyY2VudCBjaGFuZ2UsIGNhbGwgdGhhdCB0aGUgdGFrZW9mZiBkYXRlLCBhbmQgdGhlbiBhbGxpZ24gYWxsIHRoZSB0aW1lIHNlcmllcyB3aXRoIHRoYXQgZGF0ZSBhcyAwLgoKYGBge3IsIGZpZy53aWR0aD0xMiwgZmlnLmhlaWdodD0xMix3YXJuaW5nPUZBTFNFLG1lc3NhZ2U9RkFMU0UsZXJyb3I9RkFMU0V9CnBfdF9hbGxpZ25lZF9maXJzdGNvbmZpcm1lZCAgLyBwX3RfYWxsaWduZWQgCmBgYAoKCgoKIyMgUGxvdHMgYnkgQ291bnRyaWVzCgpXZSBoYXZlIHRvIGFkZCBnZW9jb2RlcyB0byB0aGUgbWFwIHBsYWNlbWVudHMKCmBgYHtyfQoKCmFkbWluMCA8LSByZWFkUkRTKCIvbWVkaWEvc2t5bmV0Mi85MDU4ODRmMC03NTQ2LTQyNzMtOTA2MS0xMmE3OTA4MzBiZWIvcndkX2dpdGh1Yl9wcml2YXRlL05FU1Njb3ZpZDE5L2RhdGFfaW4vYWRtaW4wLlJkcyIpCmFkbWluMSA8LSByZWFkUkRTKCIvbWVkaWEvc2t5bmV0Mi85MDU4ODRmMC03NTQ2LTQyNzMtOTA2MS0xMmE3OTA4MzBiZWIvcndkX2dpdGh1Yl9wcml2YXRlL05FU1Njb3ZpZDE5L2RhdGFfaW4vYWRtaW4xLlJkcyIpCmFkbWluMiA8LSByZWFkUkRTKCIvbWVkaWEvc2t5bmV0Mi85MDU4ODRmMC03NTQ2LTQyNzMtOTA2MS0xMmE3OTA4MzBiZWIvcndkX2dpdGh1Yl9wcml2YXRlL05FU1Njb3ZpZDE5L2RhdGFfaW4vYWRtaW4yLlJkcyIpCgpyZXhfY2xlYW4gPC0gZnVuY3Rpb24oeCl7IHggJT4lIHN0cmluZ2k6OnN0cmlfdHJhbnNfZ2VuZXJhbCgibGF0aW4tYXNjaWkiKSAlPiUgc3RyaW5naTo6c3RyaV9yZXBsYWNlX2FsbChyZWdleD0iW15BLVphLXowLTldIiwiIikgJT4lIHRvbG93ZXIoKSB9ICNzbyBpbmRpdmlkdWFsbHksIGVhY2ggc3RyaW5nIHNob3VsZCBiZSBkZXZvaWQgb2Ygc3BhY2VzLG5vbmNoYXJhY3RlcnMsIGFuZCBub25sYXRpbgoKcmV4X2FkbWluX2Z1bmN0aW9uIDwtIGZ1bmN0aW9uKHgpIHsKICB4ICU+JSAKICBsZWZ0X2pvaW4oYWRtaW4wICkgJT4lCiAgbGVmdF9qb2luKGFkbWluMSApICAlPiUKICBsZWZ0X2pvaW4oYWRtaW4yICkgJT4lCiAgbXV0YXRlKGdpZD1pZmVsc2UoIWlzLm5hKGFkbWluMl9uYW1lX2NsZWFuKSAmIGFkbWluMl9uYW1lX2NsZWFuIT0nJyxnaWQyLGlmZWxzZSghaXMubmEoYWRtaW4xX25hbWVfY2xlYW4pICYgYWRtaW4xX25hbWVfY2xlYW4hPScnLCBnaWQxLCBnaWQwKSkpICU+JQogIG11dGF0ZSh3aWtpZGF0YV9pZD1pZmVsc2UoIWlzLm5hKGFkbWluMl9uYW1lX2NsZWFuKSAmIGFkbWluMl9uYW1lX2NsZWFuIT0nJyx3aWtpZGF0YV9pZDIsaWZlbHNlKCFpcy5uYShhZG1pbjFfbmFtZV9jbGVhbikgJiBhZG1pbjFfbmFtZV9jbGVhbiE9JycsIHdpa2lkYXRhX2lkMSwgd2lraWRhdGFfaWQwKSkpICU+JQogIG11dGF0ZShnZW9uYW1laWQ9aWZlbHNlKCFpcy5uYShhZG1pbjJfbmFtZV9jbGVhbikgJiBhZG1pbjJfbmFtZV9jbGVhbiE9JycsZ2VvbmFtZWlkMixpZmVsc2UoIWlzLm5hKGFkbWluMV9uYW1lX2NsZWFuKSAmIGFkbWluMV9uYW1lX2NsZWFuIT0nJywgZ2VvbmFtZWlkMSwgZ2VvbmFtZWlkMCkpKSAlPiUKICBtdXRhdGUoYWRtaW5fbGV2ZWw9aWZlbHNlKCFpcy5uYShhZG1pbjJfbmFtZV9jbGVhbikgJiBhZG1pbjJfbmFtZV9jbGVhbiE9JycsMixpZmVsc2UoIWlzLm5hKGFkbWluMV9uYW1lX2NsZWFuKSAmIGFkbWluMV9uYW1lX2NsZWFuIT0nJywgMSwgMCkpKQp9CgpgYGAKCmBgYHtyLCBmaWcud2lkdGg9MTYsIGZpZy5oZWlnaHQ9MTIsd2FybmluZz1GQUxTRSxtZXNzYWdlPUZBTFNFLGVycm9yPUZBTFNFLCByZXN1bHRzPSdoaWRlJ30KaW5zdGFsbC5wYWNrYWdlcygiZ2VvZmFjZXQiKQojIG9yIGZyb20gZ2l0aHViOgojIGRldnRvb2xzOjppbnN0YWxsX2dpdGh1YigiaGFmZW4vZ2VvZmFjZXQiKQpsaWJyYXJ5KGdlb2ZhY2V0KQpoZWFkKHVzX3N0YXRlX2dyaWQyKQoKYGBgCgojIyMgQ29uZmlybWVkLCBEZWF0aHMsIFRlc3RzCgpCeSBjb3VudHJ5IAoKYGBge3IsIGZpZy53aWR0aD0xNiwgZmlnLmhlaWdodD0xMix3YXJuaW5nPUZBTFNFLG1lc3NhZ2U9RkFMU0UsZXJyb3I9RkFMU0UsIHJlc3VsdHM9J2hpZGUnfQoKZ2FkbTM2ID0gc3RfcmVhZCgiL21lZGlhL3NreW5ldDIvOTA1ODg0ZjAtNzU0Ni00MjczLTkwNjEtMTJhNzkwODMwYmViL3J3ZF9naXRodWJfcHJpdmF0ZS9ORVNTZ2FkbS9kYXRhX2luL2dhZG0zNl9ncGtnL2dhZG0zNi5ncGtnIikKZ2FkbTM2X2RmIDwtIGdhZG0zNiAlPiUgYXMuZGF0YS5mcmFtZSgpCmNvdW50cmllcyA8LSBnYWRtMzZfZGYgJT4lIGRwbHlyOjpzZWxlY3QoZ2lkPUdJRF8wLCBuYW1lPU5BTUVfMCApICU+JSBkaXN0aW5jdCgpCgp0ZW1wMSA8LSBkZl9zbG9wZXMgJT4lCiAgICAgICAgICBmaWx0ZXIoIWdpZCAlPiUgc3RyX2RldGVjdCgiXyIpICkgJT4lCiAgICAgICAgICBsZWZ0X2pvaW4oY291bnRyaWVzICU+JSBkcGx5cjo6c2VsZWN0KGdpZCwgbmFtZV90ZXh0PW5hbWUpICkgJT4lIAogICAgICAgICAgI2xlZnRfam9pbihnZW9uYW1lc19zbWFsbCAgKSAlPiUgCiAgCiAgICAgICAgICBtdXRhdGUobmFtZV90ZXh0PW5hbWVfdGV4dCAlPiUgYXMuZmFjdG9yKCkpICU+JQogICAgICAgICAgbGVmdF9qb2luKHdvcmxkX2NvdW50cmllc19ncmlkMSwgYnk9YygnZ2lkJz0nY29kZV9hbHBoYTMnKSkgJT4lCiAgICAgICAgICBmaWx0ZXIoIWlzLm5hKG5hbWUpKQp0ZW1wMiA8LSB0ZW1wMSAlPiUgYXJyYW5nZShkYXRlX2FzZGF0ZSkgJT4lIGZpbHRlcighZHVwbGljYXRlZChnaWRfZ2VvbmFtZWlkX3dpa2lkYXRhX2lkKSkgJT4lIG11dGF0ZShuYW1lX3RleHQ9bmFtZSAlPiUgYXMuZmFjdG9yKCkpCgpoZWFkKHdvcmxkX2NvdW50cmllc19ncmlkMSkKd29ybGRfY291bnRyaWVzX2dyaWQxX3JleCA8LSB3b3JsZF9jb3VudHJpZXNfZ3JpZDEgJT4lIGZpbHRlcihuYW1lICVpbiUgdGVtcDIkbmFtZSkKZGltKHdvcmxkX2NvdW50cmllc19ncmlkMV9yZXgpCmdyaWRfcHJldmlldyh3b3JsZF9jb3VudHJpZXNfZ3JpZDFfcmV4KQoKcF9jb25maXJtZWRfZGVhdGhzX3Rlc3RfYnlfY291bnRyeSA8LSB0ZW1wMSAlPiUgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2dwbG90KCkgKyAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZW9tX2xpbmUoIGFlcyh4PWRhdGVfYXNkYXRlLCB5PWNvbmZpcm1lZF9sb2dfeV9oYXQpLCBjb2xvcj0icmVkIikgKyAjICN0IGFsaWduZWQgaXMgYnJva2VuIGZvciB0aGUgVS5TLiBhbmQgc29tZSBjb3VudHJpZXMsIGFsbCBpbmZpbml0ZXMKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZW9tX2xpbmUoIGFlcyh4PWRhdGVfYXNkYXRlLCB5PWRlYXRoc19sb2dfeV9oYXQpLCBjb2xvcj0iYmxhY2siKSArICMKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZW9tX2xpbmUoIGFlcyh4PWRhdGVfYXNkYXRlLCB5PXRlc3RlZF9wZW9wbGVfbG9nX3lfaGF0KSwgY29sb3I9ImJsdWUiKSArICMKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGVtZV9idygpICsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZ3RpdGxlKCJHbG9iYWwgQ292aWQtMTk6IExvZyBUZXN0ZWQgKGJsdWUpIENvbmZpcm1lZCAocmVkKSwgRGVhdGggKGJsYWNrKSIpICsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGd1aWRlcyggY29sb3IgPSBGQUxTRSkgKwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmFjZXRfd3JhcCh+bmFtZV90ZXh0ICAgKSArCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGVtZSgKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RyaXAuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLCAgc3RyaXAudGV4dC54ID0gZWxlbWVudF9ibGFuaygpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApICsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdlb21fdGV4dChkYXRhPXRlbXAyLHg9MTgyODIrMjAseT0xNCxhZXMobGFiZWw9bmFtZV90ZXh0KSwgc2l6ZT0yLjUpICsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHlsYWIoIkNvdW50cyAobG9nKSIpICsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHhsYWIoIkRheXMgYmVmb3JlL1NpbmNlIFRha2VvZmYgaW4gQ29uZmlybWVkIE51bWJlcnMiKSArCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmYWNldF9nZW8ofm5hbWUsIGdyaWQgPXdvcmxkX2NvdW50cmllc19ncmlkMV9yZXgpIApgYGAKCmBgYHtyLCBmaWcud2lkdGg9MTYsIGZpZy5oZWlnaHQ9MTJ9CnBfY29uZmlybWVkX2RlYXRoc190ZXN0X2J5X2NvdW50cnkKYGBgCgpVLlMuIGJ5IFN0YXRlCgpgYGB7ciwgZmlnLndpZHRoPTE2LCBmaWcuaGVpZ2h0PTEyLHdhcm5pbmc9RkFMU0UsbWVzc2FnZT1GQUxTRSxlcnJvcj1GQUxTRSwgcmVzdWx0cz0naGlkZSd9Cgp0ZW1wMSA8LSBkZl9zbG9wZXMgJT4lCiAgICAgICAgICBmaWx0ZXIoZ2lkICU+JSBzdHJfZGV0ZWN0KCJVU0FcXC5bMC05XXsxLDJ9XzEkIikgKSAlPiUKICAgICAgICAgIGxlZnRfam9pbihnZW9uYW1lc19zbWFsbCAgKSAlPiUgbXV0YXRlKG5hbWVfdGV4dD0gbmFtZV90ZXh0ICU+JSBhcy5mYWN0b3IoKSkgJT4lCiAgICAgICAgICBsZWZ0X2pvaW4odXNfc3RhdGVfZ3JpZDIsIGJ5PWMoJ25hbWVfdGV4dCc9J25hbWUnKSkgJT4lIAogICAgICAgICAgZmlsdGVyKCFpcy5uYShuYW1lX3RleHQpKQp0ZW1wMiA8LSB0ZW1wMSAlPiUgYXJyYW5nZShkYXRlX2FzZGF0ZSkgJT4lIGZpbHRlcighZHVwbGljYXRlZChnaWRfZ2VvbmFtZWlkX3dpa2lkYXRhX2lkKSkgJT4lIG11dGF0ZShuYW1lX3RleHQ9bmFtZV90ZXh0ICU+JSBhcy5mYWN0b3IoKSkKCiN0X2FsbGlnbmVkCnBfY29uZmlybWVkX2RlYXRoc190ZXN0X2J5X3N0YXRlX3VzIDwtIHRlbXAxICU+JSAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICNmaWx0ZXIoZ2lkPT0iVVNBIikgJT4lICNqdXN0IGEgdGVzdAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2dwbG90KCkgKyAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdlb21fbGluZSggYWVzKHg9ZGF0ZV9hc2RhdGUsIHk9Y29uZmlybWVkX2xvZ195X2hhdCksIGNvbG9yPSJyZWQiKSArICMgI3QgYWxpZ25lZCBpcyBicm9rZW4gZm9yIHRoZSBVLlMuIGFuZCBzb21lIGNvdW50cmllcywgYWxsIGluZmluaXRlcwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2VvbV9saW5lKCBhZXMoeD1kYXRlX2FzZGF0ZSwgeT1kZWF0aHNfbG9nX3lfaGF0KSwgY29sb3I9ImJsYWNrIikgKyAjCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZW9tX2xpbmUoIGFlcyh4PWRhdGVfYXNkYXRlLCB5PXRlc3RlZF9wZW9wbGVfbG9nX3lfaGF0KSwgY29sb3I9ImJsdWUiKSArICMKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoZW1lX2J3KCkgKwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2d0aXRsZSgiQ292aWQtMTkgQnkgVS5TLiBTdGF0ZTogTG9nIFRlc3RlZCAoYmx1ZSkgQ29uZmlybWVkIChyZWQpLCBEZWF0aCAoYmxhY2spIikgKwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGVtZSgKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdHJpcC5iYWNrZ3JvdW5kID0gZWxlbWVudF9ibGFuaygpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICwgIHN0cmlwLnRleHQueCA9IGVsZW1lbnRfYmxhbmsoKQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApICsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2VvbV90ZXh0KGRhdGE9dGVtcDIseD0xODI4MisyMCx5PTEyLGFlcyhsYWJlbD1uYW1lX3RleHQpLCBzaXplPTQpICsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeWxhYigiQ291bnRzIChsb2cpIikgKyB4bGFiKCJEYXRlIikgKyAjIkRheXMgYmVmb3JlL1NpbmNlIFRha2VvZmYgaW4gQ29uZmlybWVkIE51bWJlcnMiCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGd1aWRlcyggY29sb3IgPSBGQUxTRSkgKwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmYWNldF9nZW8ofmNvZGUpIAoKIApgYGAKCmBgYHtyLCBmaWcud2lkdGg9MTYsIGZpZy5oZWlnaHQ9MTJ9CnBfY29uZmlybWVkX2RlYXRoc190ZXN0X2J5X3N0YXRlX3VzCmBgYAoKSW5kaWEgYnkgU3RhdGUKCmBgYHtyLCBmaWcud2lkdGg9MTYsIGZpZy5oZWlnaHQ9MTIsd2FybmluZz1GQUxTRSxtZXNzYWdlPUZBTFNFLGVycm9yPUZBTFNFLCByZXN1bHRzPSdoaWRlJ30KCmhlYWQoaW5kaWFfZ3JpZDIpCgppbmRpYV9ncmlkMl9yZXggPC0gaW5kaWFfZ3JpZDIgJT4lCiAgICAgICAgICAgICAgICAgICAgbXV0YXRlKGFkbWluMF9uYW1lX29yaWdpbmFsPSJJbmRpYSIpICU+JQogICAgICAgICAgICAgICAgICAgIG11dGF0ZShhZG1pbjFfbmFtZV9vcmlnaW5hbD1uYW1lKSAlPiUKICAgICAgICAgICAgICAgICAgICBtdXRhdGUoYWRtaW4yX25hbWVfb3JpZ2luYWw9JycpICAlPiUKICAgIAogICAgICAgICAgICAgICAgICAgIG11dGF0ZShhZG1pbjBfbmFtZV9jbGVhbj1hZG1pbjBfbmFtZV9vcmlnaW5hbCAlPiUgcmV4X2NsZWFuKCkpICU+JQogICAgICAgICAgICAgICAgICAgIG11dGF0ZShhZG1pbjFfbmFtZV9jbGVhbj1hZG1pbjFfbmFtZV9vcmlnaW5hbCAlPiUgcmV4X2NsZWFuKCkpICU+JQogICAgICAgICAgICAgICAgICAgIG11dGF0ZShhZG1pbjJfbmFtZV9jbGVhbj1hZG1pbjJfbmFtZV9vcmlnaW5hbCAlPiUgcmV4X2NsZWFuKCkpICU+JQogICAgICAgICAgICAgICAgICAgIHJleF9hZG1pbl9mdW5jdGlvbigpCgp0ZW1wMSA8LSBkZl9zbG9wZXMgJT4lCiAgICAgICAgICBmaWx0ZXIoZ2lkICU+JSBzdHJfZGV0ZWN0KCJJTkRcXC5bMC05XXsxLDJ9XzEkIikgKSAlPiUKICAgICAgICAgIGxlZnRfam9pbihpbmRpYV9ncmlkMl9yZXggICkgJT4lIAogICAgICAgICAgbXV0YXRlKG5hbWVfdGV4dD0gYWRtaW4xX25hbWVfb3JpZ2luYWwgJT4lIGFzLmZhY3RvcigpKSAlPiUgI3NldCBpdCB0byB0aGUgc3RhdGUncyBuYW1lCiAgICAgICAgICBmaWx0ZXIoIWlzLm5hKG5hbWVfdGV4dCkpCnRlbXAyIDwtIHRlbXAxICU+JSBhcnJhbmdlKGRhdGVfYXNkYXRlKSAlPiUgZmlsdGVyKCFkdXBsaWNhdGVkKGdpZF9nZW9uYW1laWRfd2lraWRhdGFfaWQpKSAlPiUgbXV0YXRlKG5hbWVfdGV4dD1uYW1lX3RleHQgJT4lIGFzLmZhY3RvcigpKQoKI3RfYWxsaWduZWQKcF9jb25maXJtZWRfZGVhdGhzX3Rlc3RfYnlfc3RhdGVfaW5kaWEgPC0gdGVtcDEgJT4lIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjZmlsdGVyKGdpZD09IlVTQSIpICU+JSAjanVzdCBhIHRlc3QKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2dwbG90KCkgKyAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2VvbV9saW5lKCBhZXMoeD1kYXRlX2FzZGF0ZSwgeT1jb25maXJtZWRfbG9nX3lfaGF0KSwgY29sb3I9InJlZCIpICsgIyAjdCBhbGlnbmVkIGlzIGJyb2tlbiBmb3IgdGhlIFUuUy4gYW5kIHNvbWUgY291bnRyaWVzLCBhbGwgaW5maW5pdGVzCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdlb21fbGluZSggYWVzKHg9ZGF0ZV9hc2RhdGUsIHk9ZGVhdGhzX2xvZ195X2hhdCksIGNvbG9yPSJibGFjayIpICsgIwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZW9tX2xpbmUoIGFlcyh4PWRhdGVfYXNkYXRlLCB5PXRlc3RlZF9wZW9wbGVfbG9nX3lfaGF0KSwgY29sb3I9ImJsdWUiKSArICMKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhlbWVfYncoKSArCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdndGl0bGUoIkNvdmlkLTE5IEJ5IFUuUy4gU3RhdGU6IExvZyBUZXN0ZWQgKGJsdWUpIENvbmZpcm1lZCAocmVkKSwgRGVhdGggKGJsYWNrKSIpICsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGVtZSgKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0cmlwLmJhY2tncm91bmQgPSBlbGVtZW50X2JsYW5rKCkKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAsICBzdHJpcC50ZXh0LnggPSBlbGVtZW50X2JsYW5rKCkKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApICsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZW9tX3RleHQoZGF0YT10ZW1wMix4PTE4MjgyKzUwLHk9Ny41LGFlcyhsYWJlbD1uYW1lX3RleHQpLCBzaXplPTIuNSkgKwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHlsYWIoIkNvdW50cyAobG9nKSIpICsgeGxhYigiRGF0ZSIpICsgIyJEYXlzIGJlZm9yZS9TaW5jZSBUYWtlb2ZmIGluIENvbmZpcm1lZCBOdW1iZXJzIgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGd1aWRlcyggY29sb3IgPSBGQUxTRSkgKwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICNFcnJvcjogT3RoZXIgdGhhbiAncm93JyBhbmQgJ2NvbCcsIHZhcmlhYmxlIG5hbWVzIG9mIGEgY3VzdG9tIGdyaWQgbXVzdCBiZWdpbiB3aXRoICdjb2RlJyBvciAnbmFtZScKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmYWNldF9nZW8ofmNvZGUsIGdyaWQgPSBpbmRpYV9ncmlkMiApICAjX3JleCAlPiUgZmlsdGVyKGNvZGUsIHJvdywgY29sLCBuYW1lKQoKIApgYGAKCmBgYHtyLCBmaWcud2lkdGg9MTYsIGZpZy5oZWlnaHQ9MTJ9CnBfY29uZmlybWVkX2RlYXRoc190ZXN0X2J5X3N0YXRlX2luZGlhCmBgYAoKCgoKCgpUb21vcnJvdyBtb3JuaW5nIEkgdGhpbmsgbXkgam9iIGlzIHRvIGZpcnN0IGRpZmZlcmVuY2UgYWxsIG9mIHRoZXNlLiBIb3cgbWFueSB0ZXN0cywgaG93IG1hbnkgY29uZmlybWVkLCBob3cgbWFueSBkZWFkIGVhY2ggZGF5LiBGaW5kIHRoZSBsYWdzIGFuZCBsZWFkcyB3aXRoIHRoZSBoaWdoZXN0IGNvcnJlbGF0aW9uIGJldHdlZW4gdGhvc2UgdGhyZWUsIHBvc3NpYmx5IHZhcnlpbmcgYnkgY291bnRyeS4KCgoKCgoKCldoYXQgdGhpcyBnaXZlcyB1cyBpcyBhIG5pY2Ugbm9ybWFsaXplZCBkYXRhc2V0IHdoZXJlIHRoZSB0YXNrIGlzIHRvIHByZWRpY3QgdGhlIHNoYXBlIG9mIHRoYXQgZGlzdHJpYnV0aW9uLiBXZSBjb3VsZCB0cnkgdG8gcHJlZGljdCB0aW1lIHVudGlsIHRoZSB0YWtlb2ZmLCB0aGUgaW50ZW5zaXR5IG9mIHRoZSBncm93dGggYXQgdGhlIHRha2VvZmYgcG9pbnQsIHRoZSB0aW1lIHVudGlsIGl0IHJldHVybnMgdG8gemVybywgdGhlIGFyZWEgdW5kZXIgdGhlIGN1cnZlLCBvciBldmVyeSBub29rIGFuZCBjaGFuZ2UuCgoKSG93IGRvZXMgdGVzdGluZyB2YXJ5IG92ZXIgdGhpcz8KCgpgYGB7ciwgZmlnLndpZHRoPTEyLCBmaWcuaGVpZ2h0PTEyLCBlY2hvPUZBTFNFLHdhcm5pbmc9RkFMU0UsbWVzc2FnZT1GQUxTRSxlcnJvcj1GQUxTRSwgcmVzdWx0cz0naGlkZSd9CgpwX3RfYWxsaWduZWRfdGVzdGVkX3Blb3BsZSA8LSBkZl9zbG9wZXMgJT4lIG11dGF0ZShncm91cD1wYXN0ZSh3aWtpZGF0YV9pZCkpICU+JSAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZ3Bsb3QoKSArIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdlb21fbGluZSggYWVzKHg9dF9hbGxpZ25lZCAsIHk9dGVzdGVkX3Blb3BsZV9sb2dfeV9oYXRfcGVyY2VudF9jaGFuZ2VfeV9oYXQsIGdyb3VwPWdyb3VwLCBjb2xvcj13aWtpZGF0YV9pZCksIGFscGhhPTEpICsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGVtZV9idygpICsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZ3RpdGxlKCJQZXJjZW50IERheSBvbiBEYXkgSW5jcmVhc2UgaW4gVGVzdGluZyBieSBBbGxpZ25lZCBUIikgKyB5bGltKDAsMTAwKSArCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2doaWdobGlnaHQod2lraWRhdGFfaWQgJWluJSBjKCdRMzAnLCdRMTQzOScsJ1E2NjgnLCdRODg0JywnUTE2ODYxJywnUTE1OScsJ1EzOCcpLCB1bmhpZ2hsaWdodGVkX3BhcmFtcz1saXN0KGFscGhhPS41KSkgKwogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdlb21fc21vb3RoKCBhZXMoeD10X2FsbGlnbmVkICwgeT1jb25maXJtZWRfbG9nX3lfaGF0X3BlcmNlbnRfY2hhbmdlX3lfaGF0KSwgc3BhbiA9IDAuMDUpICsgeGxpbSgtNTAsMTAwKSAKCmBgYAoKYGBge3IsIGZpZy53aWR0aD0xMiwgZmlnLmhlaWdodD0xMix3YXJuaW5nPUZBTFNFLG1lc3NhZ2U9RkFMU0UsZXJyb3I9RkFMU0V9CnBfdF9hbGxpZ25lZF90ZXN0ZWRfcGVvcGxlCmBgYAoKClBsb3Qgc29tZSBzcGVjaWZpYyBjb3VudHJpZXMKCgpgYGB7cn0KCmRmX3Nsb3BlcyAlPiUgZmlsdGVyKCFpcy5uYSh0ZXN0ZWRfcGVvcGxlKSkgJT4lIGNvdW50KHdpa2lkYXRhX2lkKSAjMjkyIHBsYWNlcyB3aXRoIHRlc3RpbmcgaW5mb3JtYXRpb24KCmRmX3Nsb3BlcyAlPiUgZmlsdGVyKHdpa2lkYXRhX2lkPT0iUTMwIikgJT4lIGdncGxvdCgpICsgZ2VvbV9saW5lKGFlcyh4PWRhdGVfYXNkYXRlLCB5PWNvbmZpcm1lZCkpICsgZ2VvbV9saW5lKGFlcyh4PWRhdGVfYXNkYXRlLCB5PXRlc3RlZF9wZW9wbGUpKQoKZGZfc2xvcGVzICU+JSBmaWx0ZXIod2lraWRhdGFfaWQ9PSJRMzAiKSAlPiUgZ2dwbG90KCkgKyBnZW9tX2xpbmUoYWVzKHg9ZGF0ZV9hc2RhdGUsIHk9Y29uZmlybWVkX2xvZ195X2hhdCkpICsgZ2VvbV9saW5lKGFlcyh4PWRhdGVfYXNkYXRlLCB5PXRlc3RlZF9wZW9wbGVfbG9nX3lfaGF0KSkKCmRmX3Nsb3BlcyAlPiUgZmlsdGVyKHdpa2lkYXRhX2lkPT0iUTMwIikgJT4lIGdncGxvdCgpICsgZ2VvbV9saW5lKGFlcyh4PWRhdGVfYXNkYXRlLCB5PWNvbmZpcm1lZC90ZXN0ZWRfcGVvcGxlKSkgCgoKZGZfc2xvcGVzICU+JSBtdXRhdGUoY29uZmlybWVkX292ZXJfdGVzdGVkX3Blb3BsZT1jb25maXJtZWQvdGVzdGVkX3Blb3BsZSkgJT4lIHB1bGwoY29uZmlybWVkX292ZXJfdGVzdGVkX3Blb3BsZSkgJT4lIHN1bW1hcnkoKQpkZl9zbG9wZXMgJT4lIG11dGF0ZShjb25maXJtZWRfb3Zlcl90ZXN0ZWRfcGVvcGxlPWNvbmZpcm1lZC90ZXN0ZWRfcGVvcGxlKSAlPiUgcHVsbChjb25maXJtZWRfb3Zlcl90ZXN0ZWRfcGVvcGxlKSAlPiUgcXVhbnRpbGUocHJvYnMgPSBzZXEoMCwgMSwgMC4xKSwgbmEucm09VCkgIzkwdGggcGVyY2VudGlhbCBpcyAsMjMKCmRmX3Nsb3BlcyAlPiUgZ2dwbG90KCkgKyBnZW9tX2xpbmUoYWVzKHg9dF9hbGxpZ25lZCwgeT1jb25maXJtZWQvdGVzdGVkX3Blb3BsZSwgY29sb3I9d2lraWRhdGFfaWQpLCBhbHBoYT0uMikgKyAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZ2hpZ2hsaWdodCh3aWtpZGF0YV9pZCAlaW4lIGMoJ1EzMCcsJ1ExNDM5JywnUTY2OCcsJ1E4ODQnLCdRMTY4NjEnLCdRMTU5JywnUTM4JyksIHVuaGlnaGxpZ2h0ZWRfcGFyYW1zPWxpc3QoYWxwaGE9LjUpKSArCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2VvbV9zbW9vdGgoIGFlcyh4PXRfYWxsaWduZWQgLCB5PWNvbmZpcm1lZC90ZXN0ZWRfcGVvcGxlKSwgc3BhbiA9IDAuMDUpICsgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeGxpbSgtNSwxMDApICsgeWxpbSgwLC4yNSkgKyB0aGVtZV9idygpICN0aGVyZSBhcmUgc29tZSBvdXRsaWFycyBub3J0aCBvZiAxMAoKCm9wdGlvbnMoZ2doaWdobGlnaHRfbWF4X2xhYmVscyA9IDYwKQpkZXRhY2goZ2doaWdobGlnaHQpCmxpYnJhcnkoZ2doaWdobGlnaHQpCmxpYnJhcnkoZGF0YS50YWJsZSkKZ2VvbmFtZXMgPC0gZnJlYWQoIi9tZWRpYS9za3luZXQyLzkwNTg4NGYwLTc1NDYtNDI3My05MDYxLTEyYTc5MDgzMGJlYi9yd2RfZ2l0aHViX3ByaXZhdGUvTkVTU2NvdmlkMTkvZGF0YV90ZW1wL2FsbENvdW50cmllcy50eHQiLCBzZXA9Ilx0IikgJT4lIG11dGF0ZV9pZihpcy5udW1lcmljLGFzLmNoYXJhY3RlcikgJT4lIG11dGF0ZV9pZihpcy5mYWN0b3IsYXMuY2hhcmFjdGVyKQpkaW0oZ2VvbmFtZXMpICMxMiwwMDYsNDI2CgpnZW9uYW1lc19zbWFsbCA8LSBnZW9uYW1lcyAlPiUgZHBseXI6OnNlbGVjdChnZW9uYW1laWQ9VjEsIG5hbWVfdGV4dD1WMikgJT4lIGlubmVyX2pvaW4oIGxoc19sb25nX2NsZWFuX2ltcHV0ZWQgJT4lIGRwbHlyOjpzZWxlY3QoZ2VvbmFtZWlkKSAlPiUgZGlzdGluY3QoKSApCmRpbShnZW9uYW1lc19zbWFsbCkKCgpkZl9zbG9wZXMgJT4lIGxlZnRfam9pbihnZW9uYW1lc19zbWFsbCAgKSAlPiUgbXV0YXRlKG5hbWVfdGV4dCAlPiUgYXMuZmFjdG9yKCkpICU+JSBmaWx0ZXIoZ2lkICU+JSBzdHJfZGV0ZWN0KCJVU0FcXC5bMC05XXsxLDJ9XzEkIikpICU+JQogICAgICAgICAgIGdncGxvdCgpICsgZ2VvbV9saW5lKGFlcyh4PXRfYWxsaWduZWQsIHk9Y29uZmlybWVkX2xvZ195X2hhdCwgY29sb3I9bmFtZV90ZXh0KSwgYWxwaGE9LjIpICsgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2doaWdobGlnaHQobWF4X2hpZ2hsaWdodCA9IDEwMEwsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2lkICU+JSBzdHJfZGV0ZWN0KCJVU0EiKSwgdW5oaWdobGlnaHRlZF9wYXJhbXM9bGlzdChhbHBoYT0uMSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdXNlX2RpcmVjdF9sYWJlbD1UKSArCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2VvbV9zbW9vdGgoIGFlcyh4PXRfYWxsaWduZWQgLCB5PWNvbmZpcm1lZF9sb2dfeV9oYXQsIHNwYW4gPSAwLjA1KSkgKyAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICB4bGltKC01LDEwMCkgKyAjeWxpbSgwLC4yNSkgKyAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGVtZV9idygpICN0aGVyZSBhcmUgc29tZSBvdXRsaWFycyBub3J0aCBvZiAxMAoKZGZfc2xvcGVzICU+JSBsZWZ0X2pvaW4oZ2VvbmFtZXNfc21hbGwgICkgJT4lIG11dGF0ZShuYW1lX3RleHQgJT4lIGFzLmZhY3RvcigpKSAlPiUgZmlsdGVyKGdpZCAlPiUgc3RyX2RldGVjdCgiVVNBXFwuWzAtOV17MSwyfV8xJCIpKSAlPiUKICAgICAgICAgICBnZ3Bsb3QoKSArIGdlb21fbGluZShhZXMoeD10X2FsbGlnbmVkLCB5PXRlc3RlZF9wZW9wbGVfbG9nX3lfaGF0LCBjb2xvcj1uYW1lX3RleHQpLCBhbHBoYT0uMikgKyAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZ2hpZ2hsaWdodChtYXhfaGlnaGxpZ2h0ID0gMTAwTCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnaWQgJT4lIHN0cl9kZXRlY3QoIlVTQSIpLCB1bmhpZ2hsaWdodGVkX3BhcmFtcz1saXN0KGFscGhhPS4xKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB1c2VfZGlyZWN0X2xhYmVsPVQpICsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZW9tX3Ntb290aCggYWVzKHg9dF9hbGxpZ25lZCAsIHk9dGVzdGVkX3Blb3BsZV9sb2dfeV9oYXQsIHNwYW4gPSAwLjA1KSkgKyAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICB4bGltKC01LDE1MCkgKyAjeWxpbSgwLC4yNSkgKyAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGVtZV9idygpICN0aGVyZSBhcmUgc29tZSBvdXRsaWFycyBub3J0aCBvZiAxMAoKZGZfc2xvcGVzICU+JSBsZWZ0X2pvaW4oZ2VvbmFtZXNfc21hbGwgICkgJT4lIG11dGF0ZShuYW1lX3RleHQgJT4lIGFzLmZhY3RvcigpKSAlPiUKICAgICAgICAgICBnZ3Bsb3QoKSArIGdlb21fbGluZShhZXMoeD10X2FsbGlnbmVkLCB5PWV4cChjb25maXJtZWRfbG9nX3lfaGF0KS9leHAodGVzdGVkX3Blb3BsZV9sb2dfeV9oYXQpLCBjb2xvcj1uYW1lX3RleHQpLCBhbHBoYT0uMikgKyAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZ2hpZ2hsaWdodChtYXhfaGlnaGxpZ2h0ID0gMTAwTCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnaWQgJT4lIHN0cl9kZXRlY3QoIlVTQSIpLCB1bmhpZ2hsaWdodGVkX3BhcmFtcz1saXN0KGFscGhhPS4xKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB1c2VfZGlyZWN0X2xhYmVsPVQpICsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZW9tX3Ntb290aCggYWVzKHg9dF9hbGxpZ25lZCAsIHk9ZXhwKGNvbmZpcm1lZF9sb2dfeV9oYXQpL2V4cCh0ZXN0ZWRfcGVvcGxlX2xvZ195X2hhdCksIHNwYW4gPSAwLjA1KSkgKyAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICB4bGltKC01LDEwMCkgKyB5bGltKDAsLjI1KSArIHRoZW1lX2J3KCkgI3RoZXJlIGFyZSBzb21lIG91dGxpYXJzIG5vcnRoIG9mIDEwCgojd2UgbWlnaHQgbmVlZCB0byBzd2l0Y2ggdGhpcyB0byBmZC4gQmVjYXVzZSBpdCdzIHRoZSBwZXJjZW50IG9mIHRoZSBuZXcgdGVzdHMgY29taW5nIGJhY2sgcG9zaXRpdmUgbm90IHRoZSBvbGQgb25lcy4KCiNSZW1pbmQgb3Vyc2VsdmVzIGludGVycHJldGF0aW9ucyB3aGVuIHdlIGxocwojaHR0cHM6Ly9kYXRhLmxpYnJhcnkudmlyZ2luaWEuZWR1L2ludGVycHJldGluZy1sb2ctdHJhbnNmb3JtYXRpb25zLWluLWEtbGluZWFyLW1vZGVsLwoKYGBgCgoKCgoKYGBge3IsIGV2YWw9Rn0KCmxtMSA8LSBsbShkZWF0aHMgfiAgY29uZmlybWVkLGRhdGE9bGhzX2xvbmdfbWVkaWFuICU+JSBmaWx0ZXIoQ0ZSPDEpKQpsbTIgPC0gbG0oZGVhdGhzIH4gdGVzdGVkX3Blb3BsZSArIGNvbmZpcm1lZCxkYXRhPWxoc19sb25nX21lZGlhbiAlPiUgZmlsdGVyKENGUjwxKSkKCmxpYnJhcnkoZ2dSYW5kb21Gb3Jlc3RzKTsgI2luc3RhbGwucGFja2FnZXMoJ2dnUmFuZG9tRm9yZXN0cycpCnJmMSA8LSByZnNyYyhkZWF0aHN+IGNvbmZpcm1lZCwKICAgICAgICAgICAgICAgICAgICAgIGRhdGE9bGhzX2xvbmdfbWVkaWFuICU+JSBmaWx0ZXIoQ0ZSPDEpICU+JSBhcy5kYXRhLmZyYW1lKCkgKQpnZ19lIDwtIGdnX2Vycm9yKHJmMSkKZ2dfdiA8LSBnZ192YXJpYWJsZShyZjEpCnBsb3QoZ2dfdiwgcGFuZWw9VFJVRSwgc2U9Ljk1LCBzcGFuPTEuMiwgYWxwaGE9LjQpIAoKcmYxIDwtIHJmc3JjKGRlYXRoc34gY29uZmlybWVkICsgdGVzdGVkX3Blb3BsZSwKICAgICAgICAgICAgICAgICAgICAgIGRhdGE9bGhzX2xvbmdfbWVkaWFuICU+JSBmaWx0ZXIoQ0ZSPDEpICU+JSBhcy5kYXRhLmZyYW1lKCkgKQpnZ19lIDwtIGdnX2Vycm9yKHJmMSkKZ2dfdiA8LSBnZ192YXJpYWJsZShyZjEpCnBsb3QoZ2dfdiwgcGFuZWw9VFJVRSwgc2U9Ljk1LCBzcGFuPTEuMiwgYWxwaGE9LjQpCgoKcmYyIDwtIHJmc3JjKENGUiB+ICB0ZXN0ZWRfcGVvcGxlX2xvZywKICAgICAgICAgICAgICAgICAgICAgIGRhdGE9bGhzX2xvbmdfbWVkaWFuICU+JSAKICAgICAgICAgICAgICAgICAgICAgIG11dGF0ZShDRlI9ZGVhdGhzL2NvbmZpcm1lZCkgJT4lCiAgICAgICAgICAgICAgICAgICAgICBtdXRhdGUodGVzdGVkX3Blb3BsZV9sb2c9bG9nKHRlc3RlZF9wZW9wbGUrMSkpICU+JQogICAgICAgICAgICAgICAgICAgICAgZmlsdGVyKENGUjwxKSAlPiUgYXMuZGF0YS5mcmFtZSgpCiAgICAgICAgICAgICApCmdnX3YgPC0gZ2dfdmFyaWFibGUocmYyKQpwbG90KGdnX3YsIHBhbmVsPVRSVUUsIHNlPS45NSwgc3Bhbj0xLjIsIGFscGhhPS40KQoKcmYyIDwtIHJmc3JjKENGUiB+ICB0ZXN0ZWRfcGVvcGxlX2xvZyArIGNvbmZpcm1lZF9sb2csCiAgICAgICAgICAgICAgICAgICAgICBkYXRhPWxoc19sb25nX21lZGlhbiAlPiUgCiAgICAgICAgICAgICAgICAgICAgICBtdXRhdGUoQ0ZSPWRlYXRocy9jb25maXJtZWQpICU+JQogICAgICAgICAgICAgICAgICAgICAgbXV0YXRlKHRlc3RlZF9wZW9wbGVfbG9nPWxvZyh0ZXN0ZWRfcGVvcGxlKzEpKSAlPiUKICAgICAgICAgICAgICAgICAgICAgIG11dGF0ZShjb25maXJtZWRfbG9nPWxvZyhjb25maXJtZWQrMSkpICU+JQogICAgICAgICAgICAgICAgICAgICAgZmlsdGVyKENGUjwxKSAlPiUgYXMuZGF0YS5mcmFtZSgpCiAgICAgICAgICAgICApCmdnX3YgPC0gZ2dfdmFyaWFibGUocmYyKQpwbG90KGdnX3YsIHBhbmVsPVRSVUUsIHNlPS45NSwgc3Bhbj0xLjIsIGFscGhhPS40KQoKCiNUaHJvdyBpbiB0aW1lCnJmMyA8LSByZnNyYyhDRlIgfiAgcG9zaXRpdmVfcGVyYyArIHRlc3RlZF9wZW9wbGVfbG9nLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkYXRhPWxoc19sb25nX21lZGlhbiAlPiUgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG11dGF0ZShDRlI9ZGVhdGhzL2NvbmZpcm1lZCkgJT4lCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG11dGF0ZShwb3NpdGl2ZV9wZXJjPWNvbmZpcm1lZC90ZXN0ZWRfcGVvcGxlKSAlPiUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbXV0YXRlKHRlc3RlZF9wZW9wbGVfbG9nPWxvZyh0ZXN0ZWRfcGVvcGxlKzEpKSAlPiUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbXV0YXRlKGNvbmZpcm1lZF9sb2c9bG9nKGNvbmZpcm1lZCsxKSkgJT4lCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbHRlcihDRlI8MSkgJT4lIGFzLmRhdGEuZnJhbWUoKQogICAgICAgICAgICAgKQpnZ192IDwtIGdnX3ZhcmlhYmxlKHJmMykKcGxvdChnZ192LCBwYW5lbD1UUlVFLCBzZT0uOTUsIHNwYW49MS4yLCBhbHBoYT0uNCkKCnBhcnRpYWxfQm9zdG9uIDwtIHBsb3QudmFyaWFibGUocmYzLApwYXJ0aWFsPVRSVUUsIHNvcnRlZD1GQUxTRSwKc2hvdy5wbG90cyA9IEZBTFNFICkKCmdnX3AgPC0gZ2dfcGFydGlhbChwYXJ0aWFsX0Jvc3RvbikKcGxvdChnZ19wLCBwYW5lbD1UUlVFLCBwb2ludHMgPSBGICkKCgpjb3BwZXJfY3RzIDwtcXVhbnRpbGVfcHRzKGxoc19sb25nX21lZGlhbiR0ZXN0ZWRfcGVvcGxlX2xvZywgZ3JvdXBzID0gNiwgaW50ZXJ2YWxzID0gVFJVRSkKcGFydGlhbF9jb3Bsb3RfQm9zdG9uIDwtIGdnX3BhcnRpYWxfY29wbG90KHJmMiwgeHZhcj0iY29uZmlybWVkX2xvZyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ3JvdXBzPXJtX2dycCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaG93LnBsb3RzPUZBTFNFKQoKCgpzdW1tYXJ5KGxoc19sb25nX21lZGlhbiRDRlIpCgpsaHNfbG9uZ19tZWRpYW4gJT4lIGZpbHRlcihjb25maXJtZWQ+MTApICU+JSBmaWx0ZXIoQ0ZSPDEpICU+JSBwdWxsKENGUikgJT4lIHN1bW1hcnkoKSAjMC4wMjk3Mjk3ICB0aGF0J3MgYSBtZWRpYW4gQ0ZSIG9mIGFib3V0IDMlCmxoc19sb25nX21lZGlhbiAlPiUgZmlsdGVyKGNvbmZpcm1lZD4xMCkgJT4lIGZpbHRlcihDRlI8MSkgJT4lIHB1bGwoQ0ZSKSAlPiUgaGlzdChicmVha3M9NTApCgpsaHNfbG9uZ19tZWRpYW4gJT4lIGZpbHRlcihjb25maXJtZWQ+MTApICU+JSBmaWx0ZXIoQ0ZSPDEpICU+JSBnZ3Bsb3QoYWVzKHg9Q0ZSKSkgKyBnZW9tX2RlbnNpdHkoKQoKCmBgYAoKCgpgYGB7ciwgZXZhbD1GfQojVGhpcyBjb2RlIGlzIG5vdyBkZXByaWNhdGVkIGluIGZhdm9yIG9mIHRoZSB0cmVlIGJhc2UgbWV0aG9kIGFib3ZlCgpwbGFjZXMgPC0gbGhzX2xvbmdfY2xlYW4kd2lraWRhdGFfaWQgJT4lIHVuaXF1ZSgpICU+JSBuYS5vbWl0KCkgOyBsZW5ndGgocGxhY2VzKQpkYXRhc2V0cyA8LSBsaHNfbG9uZ19jbGVhbiRkYXRhc2V0ICU+JSB1bmlxdWUoKSAlPiUgbmEub21pdCgpIDsgdGFibGUoZGF0YXNldCkKCnRlbXBfbGlzdCA8LSBsaXN0KCkKZm9yKHAgaW4gcGxhY2VzKXsKICAgIHByaW50KHApCiAgICBmb3IoZCBpbiBkYXRhc2V0cyl7CiAgICAgIHRlbXAgPC0gTlVMTAogICAgICB0ZW1wIDwtIGxoc19sb25nX2NsZWFuICU+JSAKICAgICAgICAgICAgICBhcnJhbmdlKGRhdGVfYXNkYXRlKSAlPiUgCiAgICAgICAgICAgICAgZmlsdGVyKGRhdGFzZXQgJWluJSBkKSAlPiUgCiAgICAgICAgICAgICAgZmlsdGVyKHdpa2lkYXRhX2lkICVpbiUgcCkgJT4lIAogICAgICAgICAgICAgIG11dGF0ZShjb25maXJtZWRfbG9nPWxvZyhjb25maXJtZWQrMSkpICU+JQogICAgICAgICAgICAgIG11dGF0ZShkZWF0aHNfbG9nPWxvZyhkZWF0aHMrMSkpICU+JQogICAgICAgICAgICAgIG11dGF0ZSh0ZXN0ZWRfcGVvcGxlX2xvZz1sb2codGVzdGVkX3Blb3BsZSsxKSkgJT4lCiAgICAgICAgICAgICAgbXV0YXRlKHQ9IGFzLm51bWVyaWMoZGF0ZV9hc2RhdGUpIC0gbWluKGFzLm51bWVyaWMoZGF0ZV9hc2RhdGUpKSArMSAgKSAlPiUgI3N0YXJ0IGF0IDEgdG8gbWFrZSBpbmRleGluZyBlYXNpZXIKICAgICAgICAgICAgICBtdXRhdGUoaT0gcm93X251bWJlcigpICApICMgYWN0dWFsbHkgbmVlZCB0aGlzCiAgICAgICAgCiAgICAgIGlfb3JpZ2luYWwgPC0gdGVtcCRpCiAgICAgIAogICAgICBpZiggbnJvdyh0ZW1wKT09MCApIHsgbmV4dH0gI3ByaW50KCJlcnJvciIpOwogICAgICBwcmludChwKQogICAgICAKICAgICAgI2JwIDwtIGJyZWFrcG9pbnRzKGNvbmZpcm1lZF9sb2cgfiAxLCBkYXRhPXRlbXApCiAgICAgIGJwIDwtIE5VTEwKICAgICAgbG0xIDwtIE5VTEwKICAgICAgeV9oYXQgPC0gTkEKICAgICAgY2RmIDwtIE5VTEwKICAgICAgdHJ5KHsKICAgICAgICAgICAgI2lmIGl0IGZhaWxzIGZhbGwgYmFjayB0byBqdXN0IGEgbG0KICAgICAgICBsbTEgPC0gbG0oY29uZmlybWVkX2xvZyB+IDEgKyB0LCBkYXRhPXRlbXApCiAgICAKICAgICAgICBjZGYgPC0gZGF0YS5mcmFtZSgKICAgICAgICAgICAgICAgICAgICAgICAgICB0PSAxLCAKICAgICAgICAgICAgICAgICAgICAgICAgICBjb25maXJtZWRfbG9nX2ludGVyY2VwdD0gY29lZihsbTEpWzFdLAogICAgICAgICAgICAgICAgICAgICAgICAgIGNvbmZpcm1lZF9sb2dfc2xvcGU9IGNvZWYobG0xKVsyXSwKICAgICAgICAgICAgICAgICAgICAgICAgICBjb25maXJtZWRfbG9nX3Nsb3BlX2JyZWFrPTAKICAgICAgICAgICAgICAgICAgICAgICAgICApCiAgICAgICAgY29uZmlybWVkX2xvZ195X2hhdD1maXR0ZWQudmFsdWVzKGxtMSkKICAgICAgfSkKICAgICAgCiAgICAgIHRyeSh7CiAgICAgICAgYnAgPC0gYnJlYWtwb2ludHMoY29uZmlybWVkX2xvZyB+IDEgKyB0LCBkYXRhPXRlbXAsIGg9MykKICAgICAgICAKICAgICAgICBjZGYgPC0gZGF0YS5mcmFtZSgKICAgICAgICAgICAgICAgICAgICAgICAgICBpPSBjKDEsYnAkYnJlYWtwb2ludHMpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICBjb25maXJtZWRfbG9nX2ludGVyY2VwdD0gY29lZihicClbLDFdLAogICAgICAgICAgICAgICAgICAgICAgICAgIGNvbmZpcm1lZF9sb2dfc2xvcGU9IGNvZWYoYnApWywyXSwKICAgICAgICAgICAgICAgICAgICAgICAgICBjb25maXJtZWRfbG9nX3Nsb3BlX2JyZWFrPTEKICAgICAgICAgICAgICAgICAgICAgICAgICApCiAgICAgICAgY29uZmlybWVkX2xvZ195X2hhdD1maXR0ZWQudmFsdWVzKGJwKQogICAgICB9KQogICAgICAKICAgICAgdHJ5KHsKICAgICAgICB0ZW1wMiA8LSB0ZW1wCiAgICAgICAgdGVtcDIkY29uZmlybWVkX2xvZ195X2hhdCA8LSBOQQogICAgICAgIHRlbXAyJGNvbmZpcm1lZF9sb2dfeV9oYXQgPC0gY29uZmlybWVkX2xvZ195X2hhdAogICAgICAgIAogICAgICAgIHRlbXAyIDwtIHRlbXAyICU+JSAKICAgICAgICAgICAgICAgIGxlZnRfam9pbihjZGYpIAogICAgICAgIHE9cGFzdGUwKHAsIl8iLGQpCiAgICAgICAgdGVtcDIgPC0gdGVtcDIgJT4lIAogICAgICAgICAgICAgICAgICBleHBhbmQoZGF0YXNldCwgZ2lkLGdlb25hbWVpZCwgd2lraWRhdGFfaWQsdD1taW4odGVtcCR0KTptYXgodGVtcCR0KSkgJT4lICNleHBhbmQgdGhpcyB0byBpbmNsdWRlIGFsbCB0aGUgdCAKICAgICAgICAgICAgICAgICAgbGVmdF9qb2luKHRlbXAyKSAlPiUgCiAgICAgICAgICAgICAgICAgIG11dGF0ZShkYXRlX2FzZGF0ZT1taW4oZGF0ZV9hc2RhdGUsIG5hLnJtPVQpLTErdCkgJT4lICNnbyBiYWNrIGludGVycCBkYXRlIGFnYWluCiAgICAgICAgICAgICAgICAgIG11dGF0ZShjb25maXJtZWRfbG9nX3Nsb3BlX2JyZWFrID0gY29uZmlybWVkX2xvZ19zbG9wZV9icmVhayAlPiUgcmVwbGFjZV9uYSgwKSAlPiUgY3Vtc3VtKCkgKSAlPiUKICAgICAgICAgICAgICAgICAgZmlsbChjb25maXJtZWRfbG9nX2ludGVyY2VwdCkgJT4lCiAgICAgICAgICAgICAgICAgIGZpbGwoY29uZmlybWVkX2xvZ19zbG9wZSkgJT4lCiAgICAgICAgICAgICAgICAgIG11dGF0ZShjb25maXJtZWRfbG9nX3lfaGF0PSBjb25maXJtZWRfbG9nX2ludGVyY2VwdCArIGNvbmZpcm1lZF9sb2dfc2xvcGUqdCApICU+JSAKICAgICAgICAgICAgICAgICAgbXV0YXRlKGNvbmZpcm1lZF9sb2dfc2xvcGVfcGVyY2VudF9jaGFuZ2UgPSByb3VuZCgoZXhwKGNvbmZpcm1lZF9sb2dfc2xvcGUpLTEpKjEwMCwyKSkgCgogICAgICAgIHRlbXBfbGlzdFtbYXMuY2hhcmFjdGVyKHEpXV0gPC0gdGVtcDIKICAgICAgfSkKICAgICAgI2lmKCBpcy5uYSggdGVtcF9saXN0W1thcy5jaGFyYWN0ZXIocSldXSR5X2hhdCkgKSB7cHJpbnQoImVycm9yIik7IGJyZWFrfQogICAgfQp9CiMiMTMwNTUiCnRlbXBfZGYgPC0gYmluZF9yb3dzKHRlbXBfbGlzdCkKZGltKHRlbXBfZGYpICNiaWdnZXIgYmVjYXVzZSB3ZSdyZSBpbnRlcnBvbGF0aW5nIG5vdwoKIyBpbnN0YWxsLnBhY2thZ2VzKCJkZXZ0b29scyIpCiNkZXZ0b29sczo6aW5zdGFsbF9naXRodWIoInRpZHl2ZXJzZS9tdWx0aWRwbHlyIikKCmxpYnJhcnkobXVsdGlkcGx5cikKbGlicmFyeShkcGx5ciwgd2Fybi5jb25mbGljdHMgPSBGQUxTRSkKI2NsdXN0ZXIgPC0gbmV3X2NsdXN0ZXIoNCkKCiNuZWVkIHRvIHN1cHJlc3MgbWVzc2FnZXMKcmV4X2Z1bmN0aW9uIDwtIGZ1bmN0aW9uKHgpewogIHRlbXA9ZGF0YS5mcmFtZShjb25maXJtZWRfbG9nX3Nsb3BlPXgpCiAgdHJ5Q2F0Y2goewogICAgI2lmIHRoZXJlJ3MgYW4gTkEgaW4geCB3ZSBnZXQgYW4gZXJyb3IgYmVjYXVzZSBicmVha3BvaW50cyBpcyBvbmUgc2hvcnQKICAgIHByZWRpY3Rpb24gPC0gYnJlYWtwb2ludHMoZm9ybXVsYT1jb25maXJtZWRfbG9nX3Nsb3BlIH4gMSwgZGF0YT10ZW1wLCBoPTMpICU+JSBmaXR0ZWQudmFsdWVzKCkKICAgIHJlc3VsdD1yZXAoTkEsIGxlbmd0aCh4KSApCiAgICByZXN1bHRbIWlzLm5hKHgpXSA8LXByZWRpY3Rpb24KICAgIHJldHVybihyZXN1bHQpCiAgICAKICB9LCBlcnJvcj1mdW5jdGlvbihlKXt9KQogIAogIHJldHVybiggcmVwKE5BLCBsZW5ndGgoeCkgKSApCiAgICAgICAgIAp9CiNkaWRuJ3QgdGFrZSB0b28gbG9uZyBub3cKCiNsaWJyYXJ5KG11bHRpZHBseXIpCiNsaWJyYXJ5KGRwbHlyLCB3YXJuLmNvbmZsaWN0cyA9IEZBTFNFKQojY2x1c3RlciA8LSBuZXdfY2x1c3Rlcig0KQoKbGlicmFyeSh0aWN0b2MpCnRpYygpCmxpYnJhcnkoc3RydWNjaGFuZ2UpCnRlc3QgPC0gdGVtcF9kZiAlPiUgaGVhZCgyMDAwMCkKdGVzdDMgPC0gdGVzdCAlPiUgCiAgICAgICAgICAgICAgICBncm91cF9ieSh3aWtpZGF0YV9pZCkgJT4lIAogICAgICAgICAgICAgICAgI3BhcnRpdGlvbihjbHVzdGVyKSAlPiUKICAgICAgICAgICAgICAgIGFycmFuZ2UoZGF0ZV9hc2RhdGUpICU+JQogICAgICAgICAgICAgICAgI211dGF0ZSggY29uZmlybWVkX2xvZ19zbG9wZV95X2hhdCA9IGJyZWFrcG9pbnRzKGZvcm11bGE9Y29uZmlybWVkX2xvZ19zbG9wZSB+IDEsIGRhdGE9LiApICU+JSBmaXR0ZWQudmFsdWVzKCkgKSAlPiUgCiAgICAgICAgICAgICAgICBtdXRhdGUoIGNvbmZpcm1lZF9sb2dfc2xvcGVfeV9oYXQgPSByZXhfZnVuY3Rpb24oY29uZmlybWVkX2xvZ19zbG9wZSkgKSAlPiUgICNmYWlscyBvbiB0aGUgY2x1c3RlcgogICAgICAgICAgICAgICAgdW5ncm91cCgpICMlPiUKICAgICAgICAgICAgICAgICNjb2xsZWN0KCkKdG9jKCkgIzQ4IHNlY29uZHMgZm9yIDEwayAjMTIyIHNlY29uZHMgZm9yIDIwawoKc2F2ZVJEUyh0ZW1wX2RmLCAiL21lZGlhL3NreW5ldDIvOTA1ODg0ZjAtNzU0Ni00MjczLTkwNjEtMTJhNzkwODMwYmViL3J3ZF9naXRodWJfcHJpdmF0ZS9ORVNTY292aWQxOS9kYXRhX3RlbXAvbGhzX2xvbmdfaW50ZXJwb2xhdGVkLlJkcyIpCgpgYGAKCgoKCgoKCgoKYGBge3IsIGV2YWw9RiwgZWNobz1GLHdhcm5pbmc9RkFMU0UsbWVzc2FnZT1GQUxTRSxlcnJvcj1GQUxTRX0KCiNIZXJlIGlzIHdoZXJlIEkgd29ya2VkIG91dCB0aGUgaWRlYSBvZiBmaXR0aW5nIHBpZWNld2lzZSBsaW5lYXIgZnVuY3Rpb25zIHRvIGVhY2ggZGF0YXNldCBpbmRlcGVuZGVudGx5LiBJdCdzIG5vdyByZXBsYWNlZCB3aXRoIGEgZnVsbHkgYXV0b21hdGVkIHBpcGxpbmUgYmFzZWQgb24gdHJlZXMuCgpjb3VudF9kYXRhc2V0cyA8LSBsaHNfbG9uZ19jbGVhbiAlPiUgZHBseXI6OnNlbGVjdCh3aWtpZGF0YV9pZCwgZGF0YXNldCkgJT4lIGRpc3RpbmN0KCkgJT4lIGNvdW50KHdpa2lkYXRhX2lkKQoKZm9ybXVsYSA9IGNvbmZpcm1lZF9sb2cgfiAxICsgZGF0ZV9yYW5rICMrIEkoZGF0ZV9yYW5rXjIpICsgSShkYXRlX3JhbmteMykKaD01CiNiZXhhciBjb3VudHkKbGlicmFyeShzdHJ1Y2NoYW5nZSkgOyAjaW5zdGFsbC5wYWNrYWdlcygnc3RydWNjaGFuZ2UnKQp0ZW1wIDwtIGxoc19sb25nX2NsZWFuICU+JSBhcnJhbmdlKGRhdGVfYXNkYXRlKSAlPiUgZmlsdGVyKHdpa2lkYXRhX2lkICVpbiUgIlExNjg2MSIpICU+JSAgbXV0YXRlKGNvbmZpcm1lZF9sb2c9bG9nKGNvbmZpcm1lZCsxKSkgJT4lCiAgICAgICAgbXV0YXRlKGRhdGVfcmFuaz0gYXMubnVtZXJpYyhkYXRlX2FzZGF0ZSkgLSBtaW4oYXMubnVtZXJpYyhkYXRlX2FzZGF0ZSkpKSAgCgp0YWJsZSh0ZW1wJGRhdGFzZXQpCgp0ZW1wX3VzYWZhY3RzIDwtIHRlbXAgJT4lIGZpbHRlcihkYXRhc2V0PT0idXNhZmFjdHMiKQpicF91c2FmYWN0cyA8LSBicmVha3BvaW50cyhmb3JtdWxhLCBkYXRhPXRlbXBfdXNhZmFjdHMsaD1oKQp0ZW1wX3VzYWZhY3RzJHlfaGF0IDwtIGZpdHRlZC52YWx1ZXMoYnBfdXNhZmFjdHMpCnRlbXBfdXNhZmFjdHMkZ3JvdXBzIDwtIDA7IHRlbXBfdXNhZmFjdHMkZ3JvdXBzW2JwX3VzYWZhY3RzJGJyZWFrcG9pbnRzKzFdIDwtIDEgOyB0ZW1wX3VzYWZhY3RzJGdyb3VwcyA8LSBjdW1zdW0odGVtcF91c2FmYWN0cyRncm91cHMpKzEKCnRlbXBfbnl0IDwtIHRlbXAgJT4lIGZpbHRlcihkYXRhc2V0PT0ibnl0IikKYnBfbnl0IDwtIGJyZWFrcG9pbnRzKGZvcm11bGEsIGRhdGE9dGVtcF9ueXQsaD1oKQp0ZW1wX255dCR5X2hhdCA8LSBmaXR0ZWQudmFsdWVzKGJwX255dCkKdGVtcF9ueXQkZ3JvdXBzIDwtIDA7IHRlbXBfbnl0JGdyb3Vwc1ticF9ueXQkYnJlYWtwb2ludHMrMV0gPC0gMSA7IHRlbXBfbnl0JGdyb3VwcyA8LSBjdW1zdW0odGVtcF9ueXQkZ3JvdXBzKSsxCgoKdGVtcF9DU1NFIDwtIHRlbXAgJT4lIGZpbHRlcihkYXRhc2V0PT0iQ1NTRSIpCmJwX0NTU0UgPC0gYnJlYWtwb2ludHMoZm9ybXVsYSwgZGF0YT10ZW1wX0NTU0UsaD1oKQp0ZW1wX0NTU0UkeV9oYXQgPC0gZml0dGVkLnZhbHVlcyhicF9DU1NFKQp0ZW1wX0NTU0UkZ3JvdXBzIDwtIDA7IHRlbXBfQ1NTRSRncm91cHNbYnBfQ1NTRSRicmVha3BvaW50cysxXSA8LSAxIDsgdGVtcF9DU1NFJGdyb3VwcyA8LSBjdW1zdW0odGVtcF9DU1NFJGdyb3VwcykrMQoKdGVtcF9iaW5nIDwtIHRlbXAgJT4lIGZpbHRlcihkYXRhc2V0PT0iYmluZyIpCmJwX2JpbmcgPC0gYnJlYWtwb2ludHMoZm9ybXVsYSwgZGF0YT10ZW1wX2JpbmcsaD1oKSAjdGhpcyBmYWlscyBiYyB0b28gZmV3CmxtX2JpbmcgPC1sbShmb3JtdWxhLCBkYXRhPXRlbXBfYmluZykKdGVtcF9iaW5nJHlfaGF0IDwtIGZpdHRlZC52YWx1ZXMobG1fYmluZykKdGVtcF9iaW5nJGdyb3VwcyA8LTEKCnRlbXBfZGYgPC0gYmluZF9yb3dzKHRlbXBfbnl0LCB0ZW1wX0NTU0UsIHRlbXBfYmluZywgdGVtcF91c2FmYWN0cykgICU+JSAKICAgICAgICAgICAgYXJyYW5nZShkYXRhc2V0LGRhdGVfYXNkYXRlKSAlPiUgCiAgICAgICAgICAgbXV0YXRlKGdyb3Vwcz1wYXN0ZShkYXRhc2V0LGdyb3VwcykpCgp0ZW1wX2RmMiA8LSBiaW5kX3Jvd3ModGVtcF9ueXQsIHRlbXBfQ1NTRSwgdGVtcF9iaW5nLCB0ZW1wX3VzYWZhY3RzKSAlPiUgCiAgICAgICAgICAgIGFycmFuZ2UoZGF0ZV9hc2RhdGUpICU+JSAKICAgICAgICAgICAgZ3JvdXBfYnkoZGF0ZV9hc2RhdGUpICU+JQogICAgICAgICAgICAgIHN1bW1hcmlzZSh5X2hhdF9tZWFuPW1lYW4oeV9oYXQsIG5hLnJtPVQpKSAlPiUKICAgICAgICAgICAgbXV0YXRlKGdyb3Vwcz05OSkKCmdncGxvdCgpICsgCiAgIGdlb21fcG9pbnQoZGF0YT10ZW1wX2RmLCBhZXMoeD1kYXRlX2FzZGF0ZSwgeT1jb25maXJtZWRfbG9nLCBjb2xvcj1kYXRhc2V0KSkgKwogICBnZW9tX2xpbmUoZGF0YT10ZW1wX2RmLCBhZXMoeD1kYXRlX2FzZGF0ZSwgeT15X2hhdCwgY29sb3I9ZGF0YXNldCwgZ3JvdXA9Z3JvdXBzKSkgKwogICAjZ2VvbV9saW5lKGRhdGE9dGVtcF9kZjIsIGFlcyh4PWRhdGVfYXNkYXRlLCB5PXlfaGF0X21lYW4pLCBjb2xvcj0iYmxhY2siLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSArCiAgIHRoZW1lX2J3KCkgKwogICBnZ3RpdGxlKCJCZXhhciBDb3VudHkgKFExNjg2MSkgQ29uZmlybWVkIikKCgoKIyMjIyMKI0NoaW5hIFExNDgKdGVtcCA8LSBsaHNfbG9uZ19jbGVhbiAlPiUgYXJyYW5nZShkYXRlX2FzZGF0ZSkgJT4lIAogICAgICAgIGZpbHRlcih3aWtpZGF0YV9pZCAlaW4lICJRMTQ4IikgJT4lIAogICAgICAgIGdyb3VwX2J5KGRhdGFzZXQsIGRhdGVfYXNkYXRlKSAlPiUKICAgICAgICAgIHN1bW1hcmlzZShjb25maXJtZWQ9bWF4KGNvbmZpcm1lZCwgbmEucm09VCkgKSAlPiUgI3RoaXMgaXMgYSBwcm9ibGVtIGR1cGVzIHdpdGggdGhlIHNhbWUgZGF0ZSAgI3RoaXMgZml4ZXMgYSBsb3Qgb2YgdGhpbmdzIGJ1dCB3ZSBuZWVkIHRvIGZpZ3VyZSBvdXQgdGhlIG9yaWdpbiBvZiB0aGlzIHByb2JsZW0KICAgICAgICB1bmdyb3VwKCkgJT4lCiAgICAgICAgbXV0YXRlKGNvbmZpcm1lZF9sb2c9bG9nKGNvbmZpcm1lZCsxKSkgJT4lIAogICAgICAgIG11dGF0ZShkYXRlX3Jhbms9IGFzLm51bWVyaWMoZGF0ZV9hc2RhdGUpIC0gbWluKGFzLm51bWVyaWMoZGF0ZV9hc2RhdGUpKSkgIAoKCnRlbXBfd2lraXBlZGlhIDwtIHRlbXAgJT4lIGZpbHRlcihkYXRhc2V0PT0id2lraXBlZGlhIikKYnBfd2lraXBlZGlhIDwtIGJyZWFrcG9pbnRzKGZvcm11bGEsIGRhdGE9dGVtcF93aWtpcGVkaWEsaD1oKQp0ZW1wX3dpa2lwZWRpYSR5X2hhdCA8LSBmaXR0ZWQudmFsdWVzKGJwX3dpa2lwZWRpYSkKdGVtcF93aWtpcGVkaWEkZ3JvdXBzIDwtIDA7IHRlbXBfd2lraXBlZGlhJGdyb3Vwc1ticF93aWtpcGVkaWEkYnJlYWtwb2ludHMrMV0gPC0gMSA7IHRlbXBfd2lraXBlZGlhJGdyb3VwcyA8LSBjdW1zdW0odGVtcF93aWtpcGVkaWEkZ3JvdXBzKSsxCgoKdGVtcF9lY2RjIDwtIHRlbXAgJT4lIGZpbHRlcihkYXRhc2V0PT0iZWNkYyIpCmJwX2VjZGMgPC0gYnJlYWtwb2ludHMoZm9ybXVsYSwgZGF0YT10ZW1wX2VjZGMsaD1oKQp0ZW1wX2VjZGMkeV9oYXQgPC0gZml0dGVkLnZhbHVlcyhicF9lY2RjKQp0ZW1wX2VjZGMkZ3JvdXBzIDwtIDA7IHRlbXBfZWNkYyRncm91cHNbYnBfZWNkYyRicmVha3BvaW50cysxXSA8LSAxIDsgdGVtcF9lY2RjJGdyb3VwcyA8LSBjdW1zdW0odGVtcF9lY2RjJGdyb3VwcykrMQoKdGVtcF93aG8gPC0gdGVtcCAlPiUgZmlsdGVyKGRhdGFzZXQ9PSJ3aG8iKQpicF93aG8gPC0gYnJlYWtwb2ludHMoZm9ybXVsYSwgZGF0YT10ZW1wX3dobyxoPWgpCnRlbXBfd2hvJHlfaGF0IDwtIGZpdHRlZC52YWx1ZXMoYnBfd2hvKQp0ZW1wX3dobyRncm91cHMgPC0gMDsgdGVtcF93aG8kZ3JvdXBzW2JwX3dobyRicmVha3BvaW50cysxXSA8LSAxIDsgdGVtcF93aG8kZ3JvdXBzIDwtIGN1bXN1bSh0ZW1wX3dobyRncm91cHMpKzEKCgp0ZW1wX21ldGFiaW90YSA8LSB0ZW1wICU+JSBmaWx0ZXIoZGF0YXNldD09Im1ldGFiaW90YSIpCmJwX21ldGFiaW90YSA8LSBicmVha3BvaW50cyhmb3JtdWxhLCBkYXRhPXRlbXBfbWV0YWJpb3RhLGg9aCkKdGVtcF9tZXRhYmlvdGEkeV9oYXQgPC0gZml0dGVkLnZhbHVlcyhicF9tZXRhYmlvdGEpCnRlbXBfbWV0YWJpb3RhJGdyb3VwcyA8LSAwOyB0ZW1wX21ldGFiaW90YSRncm91cHNbYnBfbWV0YWJpb3RhJGJyZWFrcG9pbnRzKzFdIDwtIDEgOyB0ZW1wX21ldGFiaW90YSRncm91cHMgPC0gY3Vtc3VtKHRlbXBfbWV0YWJpb3RhJGdyb3VwcykrMQoKdGVtcF9iaW5nIDwtIHRlbXAgJT4lIGZpbHRlcihkYXRhc2V0PT0iYmluZyIpCmJwX2JpbmcgPC0gYnJlYWtwb2ludHMoZm9ybXVsYSwgZGF0YT10ZW1wX2JpbmcsaD1oKSAjdGhpcyBmYWlscyBiYyB0b28gZmV3CmxtX2JpbmcgPC1sbShmb3JtdWxhLCBkYXRhPXRlbXBfYmluZykKdGVtcF9iaW5nJHlfaGF0IDwtIGZpdHRlZC52YWx1ZXMobG1fYmluZykKdGVtcF9iaW5nJGdyb3VwcyA8LTEKCnRlbXBfZGYgPC0gYmluZF9yb3dzKHRlbXBfZWNkYywgdGVtcF9tZXRhYmlvdGEsIHRlbXBfYmluZywgdGVtcF93aG8sIHRlbXBfd2lraXBlZGlhKSAlPiUgCiAgICAgICAgICAgIGFycmFuZ2UoZGF0YXNldCxkYXRlX2FzZGF0ZSkgJT4lIAogICAgICAgICAgIG11dGF0ZShncm91cHM9cGFzdGUoZGF0YXNldCxncm91cHMpKQoKdGVtcF9kZjIgPC0gYmluZF9yb3dzKHRlbXBfZWNkYywgdGVtcF9tZXRhYmlvdGEsIHRlbXBfYmluZywgdGVtcF93aG8sIHRlbXBfd2lraXBlZGlhKSAlPiUgCiAgICAgICAgICAgIGFycmFuZ2UoZGF0ZV9hc2RhdGUpICU+JSAKICAgICAgICAgICAgZ3JvdXBfYnkoZGF0ZV9hc2RhdGUpICU+JQogICAgICAgICAgICAgIHN1bW1hcmlzZSh5X2hhdF9tZWFuPW1lYW4oeV9oYXQsIG5hLnJtPVQpKSAlPiUKICAgICAgICAgICAgbXV0YXRlKGdyb3Vwcz05OSkKCmdncGxvdCgpICsgCiAgIGdlb21fcG9pbnQoZGF0YT10ZW1wX2RmLCBhZXMoeD1kYXRlX2FzZGF0ZSwgeT1jb25maXJtZWRfbG9nLCBjb2xvcj1kYXRhc2V0KSkgKwogICBnZW9tX2xpbmUoZGF0YT10ZW1wX2RmLCBhZXMoeD1kYXRlX2FzZGF0ZSwgeT15X2hhdCwgY29sb3I9ZGF0YXNldCwgZ3JvdXA9Z3JvdXBzKSkgKwogICAjZ2VvbV9saW5lKGRhdGE9dGVtcF9kZjIsIGFlcyh4PWRhdGVfYXNkYXRlLCB5PXlfaGF0X21lYW4pLCBjb2xvcj0iYmxhY2siLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSArCiAgIHRoZW1lX2J3KCkgKwogICBnZ3RpdGxlKCJDaGluYSAoUTE0OCkgQ29uZmlybWVkIikKICAgI2dlb21fdmxpbmUoeGludGVyY2VwdD1icCRicmVha3BvaW50cykKCgojSW5kaWEKIyJRNjY4Igp0ZW1wIDwtIGxoc19sb25nX2NsZWFuICU+JSBhcnJhbmdlKGRhdGVfYXNkYXRlKSAlPiUgCiAgICAgICAgZmlsdGVyKHdpa2lkYXRhX2lkICVpbiUgIlE2NjgiKSAlPiUgCiAgICAgICAgZ3JvdXBfYnkoZGF0YXNldCwgZGF0ZV9hc2RhdGUpICU+JQogICAgICAgICAgc3VtbWFyaXNlKGNvbmZpcm1lZD1tYXgoY29uZmlybWVkLCBuYS5ybT1UKSApICU+JSAjdGhpcyBpcyBhIHByb2JsZW0gZHVwZXMgd2l0aCB0aGUgc2FtZSBkYXRlICAjdGhpcyBmaXhlcyBhIGxvdCBvZiB0aGluZ3MgYnV0IHdlIG5lZWQgdG8gZmlndXJlIG91dCB0aGUgb3JpZ2luIG9mIHRoaXMgcHJvYmxlbQogICAgICAgIHVuZ3JvdXAoKSAlPiUKICAgICAgICBtdXRhdGUoY29uZmlybWVkX2xvZz1sb2coY29uZmlybWVkKzEpKSAlPiUgCiAgICAgICAgbXV0YXRlKGRhdGVfcmFuaz0gYXMubnVtZXJpYyhkYXRlX2FzZGF0ZSkgLSBtaW4oYXMubnVtZXJpYyhkYXRlX2FzZGF0ZSkpKSAgCnRhYmxlKHRlbXAkZGF0YXNldCkKCnRlbXBfY292aWQxOWluZGlhIDwtIHRlbXAgJT4lIGZpbHRlcihkYXRhc2V0PT0iY292aWQxOWluZGlhIikKYnBfY292aWQxOWluZGlhIDwtIGJyZWFrcG9pbnRzKGZvcm11bGEsIGRhdGE9dGVtcF9jb3ZpZDE5aW5kaWEsaD1oKQp0ZW1wX2NvdmlkMTlpbmRpYSR5X2hhdCA8LSBmaXR0ZWQudmFsdWVzKGJwX2NvdmlkMTlpbmRpYSkKdGVtcF9jb3ZpZDE5aW5kaWEkZ3JvdXBzIDwtIDA7IHRlbXBfY292aWQxOWluZGlhJGdyb3Vwc1ticF9jb3ZpZDE5aW5kaWEkYnJlYWtwb2ludHMrMV0gPC0gMSA7IHRlbXBfY292aWQxOWluZGlhJGdyb3VwcyA8LSBjdW1zdW0odGVtcF9jb3ZpZDE5aW5kaWEkZ3JvdXBzKSsxCgp0ZW1wX3dpa2lwZWRpYSA8LSB0ZW1wICU+JSBmaWx0ZXIoZGF0YXNldD09Indpa2lwZWRpYSIpCmJwX3dpa2lwZWRpYSA8LSBicmVha3BvaW50cyhmb3JtdWxhLCBkYXRhPXRlbXBfd2lraXBlZGlhLGg9aCkKdGVtcF93aWtpcGVkaWEkeV9oYXQgPC0gZml0dGVkLnZhbHVlcyhicF93aWtpcGVkaWEpCnRlbXBfd2lraXBlZGlhJGdyb3VwcyA8LSAwOyB0ZW1wX3dpa2lwZWRpYSRncm91cHNbYnBfd2lraXBlZGlhJGJyZWFrcG9pbnRzKzFdIDwtIDEgOyB0ZW1wX3dpa2lwZWRpYSRncm91cHMgPC0gY3Vtc3VtKHRlbXBfd2lraXBlZGlhJGdyb3VwcykrMQoKdGVtcF9DU1NFIDwtIHRlbXAgJT4lIGZpbHRlcihkYXRhc2V0PT0iQ1NTRSIpCmJwX0NTU0UgPC0gYnJlYWtwb2ludHMoZm9ybXVsYSwgZGF0YT10ZW1wX0NTU0UsaD1oKQp0ZW1wX0NTU0UkeV9oYXQgPC0gZml0dGVkLnZhbHVlcyhicF9DU1NFKQp0ZW1wX0NTU0UkZ3JvdXBzIDwtIDA7IHRlbXBfQ1NTRSRncm91cHNbYnBfQ1NTRSRicmVha3BvaW50cysxXSA8LSAxIDsgdGVtcF9DU1NFJGdyb3VwcyA8LSBjdW1zdW0odGVtcF9DU1NFJGdyb3VwcykrMQoKdGVtcF9lY2RjIDwtIHRlbXAgJT4lIGZpbHRlcihkYXRhc2V0PT0iZWNkYyIpCmJwX2VjZGMgPC0gYnJlYWtwb2ludHMoZm9ybXVsYSwgZGF0YT10ZW1wX2VjZGMsaD1oKQp0ZW1wX2VjZGMkeV9oYXQgPC0gZml0dGVkLnZhbHVlcyhicF9lY2RjKQp0ZW1wX2VjZGMkZ3JvdXBzIDwtIDA7IHRlbXBfZWNkYyRncm91cHNbYnBfZWNkYyRicmVha3BvaW50cysxXSA8LSAxIDsgdGVtcF9lY2RjJGdyb3VwcyA8LSBjdW1zdW0odGVtcF9lY2RjJGdyb3VwcykrMQoKdGVtcF93aG8gPC0gdGVtcCAlPiUgZmlsdGVyKGRhdGFzZXQ9PSJ3aG8iKQpicF93aG8gPC0gYnJlYWtwb2ludHMoZm9ybXVsYSwgZGF0YT10ZW1wX3dobyxoPWgpCnRlbXBfd2hvJHlfaGF0IDwtIGZpdHRlZC52YWx1ZXMoYnBfd2hvKQp0ZW1wX3dobyRncm91cHMgPC0gMDsgdGVtcF93aG8kZ3JvdXBzW2JwX3dobyRicmVha3BvaW50cysxXSA8LSAxIDsgdGVtcF93aG8kZ3JvdXBzIDwtIGN1bXN1bSh0ZW1wX3dobyRncm91cHMpKzEKCnRlbXBfbWV0YWJpb3RhIDwtIHRlbXAgJT4lIGZpbHRlcihkYXRhc2V0PT0ibWV0YWJpb3RhIikKYnBfbWV0YWJpb3RhIDwtIGJyZWFrcG9pbnRzKGZvcm11bGEsIGRhdGE9dGVtcF9tZXRhYmlvdGEsaD1oKQp0ZW1wX21ldGFiaW90YSR5X2hhdCA8LSBmaXR0ZWQudmFsdWVzKGJwX21ldGFiaW90YSkKdGVtcF9tZXRhYmlvdGEkZ3JvdXBzIDwtIDA7IHRlbXBfbWV0YWJpb3RhJGdyb3Vwc1ticF9tZXRhYmlvdGEkYnJlYWtwb2ludHMrMV0gPC0gMSA7IHRlbXBfbWV0YWJpb3RhJGdyb3VwcyA8LSBjdW1zdW0odGVtcF9tZXRhYmlvdGEkZ3JvdXBzKSsxCgp0ZW1wX2JpbmcgPC0gdGVtcCAlPiUgZmlsdGVyKGRhdGFzZXQ9PSJiaW5nIikKYnBfYmluZyA8LSBicmVha3BvaW50cyhmb3JtdWxhLCBkYXRhPXRlbXBfYmluZyxoPWgpICN0aGlzIGZhaWxzIGJjIHRvbyBmZXcKbG1fYmluZyA8LWxtKGZvcm11bGEsIGRhdGE9dGVtcF9iaW5nKQp0ZW1wX2JpbmckeV9oYXQgPC0gZml0dGVkLnZhbHVlcyhsbV9iaW5nKQp0ZW1wX2JpbmckZ3JvdXBzIDwtMQoKdGVtcF9kZiA8LSBiaW5kX3Jvd3ModGVtcF9jb3ZpZDE5aW5kaWEsIHRlbXBfd2lraXBlZGlhLCB0ZW1wX0NTU0UsIHRlbXBfZWNkYywgdGVtcF93aG8sIHRlbXBfbWV0YWJpb3RhLCB0ZW1wX2JpbmcpICU+JSAKICAgICAgICAgICAgYXJyYW5nZShkYXRhc2V0LGRhdGVfYXNkYXRlKSAlPiUgCiAgICAgICAgICAgbXV0YXRlKGdyb3Vwcz1wYXN0ZShkYXRhc2V0LGdyb3VwcykpCgp0ZW1wX2RmMiA8LSBiaW5kX3Jvd3ModGVtcF9jb3ZpZDE5aW5kaWEsIHRlbXBfd2lraXBlZGlhLCB0ZW1wX0NTU0UsIHRlbXBfZWNkYywgdGVtcF93aG8sIHRlbXBfbWV0YWJpb3RhLCB0ZW1wX2JpbmcpICU+JSAKICAgICAgICAgICAgYXJyYW5nZShkYXRlX2FzZGF0ZSkgJT4lIAogICAgICAgICAgICBncm91cF9ieShkYXRlX2FzZGF0ZSkgJT4lCiAgICAgICAgICAgICAgc3VtbWFyaXNlKHlfaGF0X21lYW49bWVhbih5X2hhdCwgbmEucm09VCkpICU+JQogICAgICAgICAgICBtdXRhdGUoZ3JvdXBzPTk5KQoKZ2dwbG90KCkgKyAKICAgZ2VvbV9wb2ludChkYXRhPXRlbXBfZGYsIGFlcyh4PWRhdGVfYXNkYXRlLCB5PWNvbmZpcm1lZF9sb2csIGNvbG9yPWRhdGFzZXQpLCBhbHBoYT0uMykgKwogICBnZW9tX2xpbmUoZGF0YT10ZW1wX2RmLCBhZXMoeD1kYXRlX2FzZGF0ZSwgeT15X2hhdCwgY29sb3I9ZGF0YXNldCwgZ3JvdXA9Z3JvdXBzKSkgKwogICAjZ2VvbV9saW5lKGRhdGE9dGVtcF9kZjIsIGFlcyh4PWRhdGVfYXNkYXRlLCB5PXlfaGF0X21lYW4pLCBjb2xvcj0iYmxhY2siLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSArCiAgIHRoZW1lX2J3KCkgKwogICBnZ3RpdGxlKCJJbmRpYSAoUTY2OCkgQ29uZmlybWVkIikKCgojRmxvcmlkYQojUTgxMgp0ZW1wIDwtIGxoc19sb25nX2NsZWFuICU+JSBhcnJhbmdlKGRhdGVfYXNkYXRlKSAlPiUgCiAgICAgICAgZmlsdGVyKHdpa2lkYXRhX2lkICVpbiUgIlE4MTIiKSAlPiUgCiAgICAgICAgZ3JvdXBfYnkoZGF0YXNldCwgZGF0ZV9hc2RhdGUpICU+JQogICAgICAgICAgc3VtbWFyaXNlKGNvbmZpcm1lZD1tYXgoY29uZmlybWVkLCBuYS5ybT1UKSApICU+JSAjdGhpcyBpcyBhIHByb2JsZW0gZHVwZXMgd2l0aCB0aGUgc2FtZSBkYXRlICAjdGhpcyBmaXhlcyBhIGxvdCBvZiB0aGluZ3MgYnV0IHdlIG5lZWQgdG8gZmlndXJlIG91dCB0aGUgb3JpZ2luIG9mIHRoaXMgcHJvYmxlbQogICAgICAgIHVuZ3JvdXAoKSAlPiUKICAgICAgICBtdXRhdGUoY29uZmlybWVkX2xvZz1sb2coY29uZmlybWVkKzEpKSAlPiUKICAgICAgICBtdXRhdGUoZGF0ZV9yYW5rPSBhcy5udW1lcmljKGRhdGVfYXNkYXRlKSAtIG1pbihhcy5udW1lcmljKGRhdGVfYXNkYXRlKSkpICAKdGFibGUodGVtcCRkYXRhc2V0KQoKdGVtcF9jb3ZpZHRyYWNraW5nIDwtIHRlbXAgJT4lIGZpbHRlcihkYXRhc2V0PT0iY292aWR0cmFja2luZyIpCmJwX2NvdmlkdHJhY2tpbmcgPC0gYnJlYWtwb2ludHMoZm9ybXVsYSwgZGF0YT10ZW1wX2NvdmlkdHJhY2tpbmcsaD1oKQp0ZW1wX2NvdmlkdHJhY2tpbmckeV9oYXQgPC0gZml0dGVkLnZhbHVlcyhicF9jb3ZpZHRyYWNraW5nKQp0ZW1wX2NvdmlkdHJhY2tpbmckZ3JvdXBzIDwtIDA7IHRlbXBfY292aWR0cmFja2luZyRncm91cHNbYnBfY292aWR0cmFja2luZyRicmVha3BvaW50cysxXSA8LSAxIDsgdGVtcF9jb3ZpZHRyYWNraW5nJGdyb3VwcyA8LSBjdW1zdW0odGVtcF9jb3ZpZHRyYWNraW5nJGdyb3VwcykrMQoKdGVtcF93aWtpcGVkaWEgPC0gdGVtcCAlPiUgZmlsdGVyKGRhdGFzZXQ9PSJ3aWtpcGVkaWEiKQpicF93aWtpcGVkaWEgPC0gYnJlYWtwb2ludHMoZm9ybXVsYSwgZGF0YT10ZW1wX3dpa2lwZWRpYSxoPWgpCnRlbXBfd2lraXBlZGlhJHlfaGF0IDwtIGZpdHRlZC52YWx1ZXMoYnBfd2lraXBlZGlhKQp0ZW1wX3dpa2lwZWRpYSRncm91cHMgPC0gMDsgdGVtcF93aWtpcGVkaWEkZ3JvdXBzW2JwX3dpa2lwZWRpYSRicmVha3BvaW50cysxXSA8LSAxIDsgdGVtcF93aWtpcGVkaWEkZ3JvdXBzIDwtIGN1bXN1bSh0ZW1wX3dpa2lwZWRpYSRncm91cHMpKzEKCnRlbXBfbWV0YWJpb3RhIDwtIHRlbXAgJT4lIGZpbHRlcihkYXRhc2V0PT0ibWV0YWJpb3RhIikKYnBfbWV0YWJpb3RhIDwtIGJyZWFrcG9pbnRzKGZvcm11bGEsIGRhdGE9dGVtcF9tZXRhYmlvdGEsaD1oKQp0ZW1wX21ldGFiaW90YSR5X2hhdCA8LSBmaXR0ZWQudmFsdWVzKGJwX21ldGFiaW90YSkKdGVtcF9tZXRhYmlvdGEkZ3JvdXBzIDwtIDA7IHRlbXBfbWV0YWJpb3RhJGdyb3Vwc1ticF9tZXRhYmlvdGEkYnJlYWtwb2ludHMrMV0gPC0gMSA7IHRlbXBfbWV0YWJpb3RhJGdyb3VwcyA8LSBjdW1zdW0odGVtcF9tZXRhYmlvdGEkZ3JvdXBzKSsxCgp0ZW1wX2JpbmcgPC0gdGVtcCAlPiUgZmlsdGVyKGRhdGFzZXQ9PSJiaW5nIikKYnBfYmluZyA8LSBicmVha3BvaW50cyhmb3JtdWxhLCBkYXRhPXRlbXBfYmluZyxoPWgpICN0aGlzIGZhaWxzIGJjIHRvbyBmZXcKbG1fYmluZyA8LWxtKGZvcm11bGEsIGRhdGE9dGVtcF9iaW5nKQp0ZW1wX2JpbmckeV9oYXQgPC0gZml0dGVkLnZhbHVlcyhsbV9iaW5nKQp0ZW1wX2JpbmckZ3JvdXBzIDwtMQoKdGVtcF9kZiA8LSBiaW5kX3Jvd3ModGVtcF9jb3ZpZHRyYWNraW5nLCB0ZW1wX3dpa2lwZWRpYSwgdGVtcF9tZXRhYmlvdGEsIHRlbXBfYmluZykgJT4lIAogICAgICAgICAgICBhcnJhbmdlKGRhdGFzZXQsZGF0ZV9hc2RhdGUpICU+JSAKICAgICAgICAgICBtdXRhdGUoZ3JvdXBzPXBhc3RlKGRhdGFzZXQsZ3JvdXBzKSkKCnRlbXBfZGYyIDwtIGJpbmRfcm93cyh0ZW1wX2NvdmlkdHJhY2tpbmcsIHRlbXBfd2lraXBlZGlhLCB0ZW1wX21ldGFiaW90YSwgdGVtcF9iaW5nKSAlPiUgCiAgICAgICAgICAgIGFycmFuZ2UoZGF0ZV9hc2RhdGUpICU+JSAKICAgICAgICAgICAgZ3JvdXBfYnkoZGF0ZV9hc2RhdGUpICU+JQogICAgICAgICAgICAgIHN1bW1hcmlzZSh5X2hhdF9tZWFuPW1lYW4oeV9oYXQsIG5hLnJtPVQpKSAlPiUKICAgICAgICAgICAgbXV0YXRlKGdyb3Vwcz05OSkKCmdncGxvdCgpICsgCiAgIGdlb21fcG9pbnQoZGF0YT10ZW1wX2RmLCBhZXMoeD1kYXRlX2FzZGF0ZSwgeT1jb25maXJtZWRfbG9nLCBjb2xvcj1kYXRhc2V0KSwgYWxwaGE9LjMpICsKICAgZ2VvbV9saW5lKGRhdGE9dGVtcF9kZiwgYWVzKHg9ZGF0ZV9hc2RhdGUsIHk9eV9oYXQsIGNvbG9yPWRhdGFzZXQsIGdyb3VwPWdyb3VwcykpICsKICAgI2dlb21fbGluZShkYXRhPXRlbXBfZGYyLCBhZXMoeD1kYXRlX2FzZGF0ZSwgeT15X2hhdF9tZWFuKSwgY29sb3I9ImJsYWNrIiwgbGluZXR5cGUgPSAiZGFzaGVkIikgKwogICB0aGVtZV9idygpICsKICAgZ2d0aXRsZSgiRmxvcmlkYSAoUTgxMikgQ29uZmlybWVkIikKCmBgYAoKCgpgYGB7ciwgZXZhbD1GLCBlY2hvPUYsd2FybmluZz1GQUxTRSxtZXNzYWdlPUZBTFNFLGVycm9yPUZBTFNFfQojQXMgd2FzIHRoaXMgcGFydAojICMgUTY2OCAgUTE2ODYxICBRMTQ4ICBRMzAgUTE0OCBRMTY4NjEgUTMwCnRlbXAgPC0gdGVtcF9kZiAlPiUgZmlsdGVyKHdpa2lkYXRhX2lkPT0iUTE0OCIpICU+JSBtdXRhdGUoZGF0ZV9hc251bWVyaWM9YXMubnVtZXJpYyhkYXRlX2FzZGF0ZSkpCnRlbXAgJT4lIGdncGxvdCgpICsgZ2VvbV9wb2ludChhZXMoZGF0ZV9hc2RhdGUsY29uZmlybWVkX2xvZykpICArIGZhY2V0X3dyYXAofmRhdGFzZXQpICMrIGdlb21fcG9pbnQoYWVzKGRhdGVfYXNkYXRlLGNvbmZpcm1lZF9sb2dfeV9oYXQpLCBjb2xvcj0iYmx1ZSIpCgojbGlicmFyeShycGFydCkKI3J0IDwtIHJwYXJ0KGNvbmZpcm1lZF9sb2cgfiAxICsgZGF0ZV9hc2RhdGUgLCBkYXRhPXRlbXApCiN0ZW1wJHlfaGF0IDwtIHByZWRpY3QoIHJ0LCBuZXdkYXRhPXRlbXAgKQoKI3RlbXAkZGF0YXNldCA8LSBhcy5mYWN0b3IodGVtcCRkYXRhc2V0KQojZm1CSCA8LSBtb2IoY29uZmlybWVkX2xvZyB+IDEgKyB0ICsgSSh0XjIpICsgSSh0XjMpIHwgdCArIGRhdGFzZXQsIGNvbnRyb2wgPSBtb2JfY29udHJvbChtaW5zcGxpdCA9IDMpLCBkYXRhID0gdGVtcCwgIG1vZGVsID0gbGluZWFyTW9kZWwpICN0aGlzIGZpdHMgYSBwaWVjZXdpc2UgbGluZWFyIHRvIGVhY2ggZGF0YXNldCAjaGF2ZSB0byB1c2UgdCwgZG9lc24ndCBsaWtlIGRhdGEgb2JqZWN0cwojcGxvdChmbUJIKQojY29lZihmbUJIKQojdGVtcCR5X2hhdCA8LSBwcmVkaWN0KCBmbUJILCBuZXdkYXRhPXRlbXAgKQoKI1RoZSB0cmljayBpcyBmaXR0aW5nIG9ubHkgdG8gb25lIGRhdGFzZXQgYXQgYSB0aW1lCnRlbXBfbGlzdCA8LSBsaXN0KCkKZm9yKCBkIGluIHRlbXAkZGF0YXNldCAlPiUgdW5pcXVlKCkgKXsKICB0ZW1wdGVtcCA8LSB0ZW1wICU+JSBmaWx0ZXIoZGF0YXNldD09ZCkKICBmbUJIIDwtIG1vYihjb25maXJtZWRfbG9nIH4gMSArIGRhdGVfYXNudW1lcmljICAgIHwgZGF0ZV9hc251bWVyaWMgLCBjb250cm9sID0gbW9iX2NvbnRyb2wobWluc3BsaXQgPSAzLCBhbHBoYT0uMiksIGRhdGEgPSB0ZW1wdGVtcCwgIG1vZGVsID0gbGluZWFyTW9kZWwpICAjICsgSShkYXRlX2FzbnVtZXJpY14yKSAgICAgKyBJKHReMykgICMgKyBJKHReMikgKyBJKHReMykgKyBJKHReNCkgKyBJKHReMikgCiAgdGVtcHRlbXAkeV9oYXQgPC0gcHJlZGljdCggZm1CSCwgbmV3ZGF0YT10ZW1wdGVtcCAsIHR5cGUgPSBjKCJyZXNwb25zZSIpICkKICB0ZW1wdGVtcCRncm91cF9udW1iZXIgPC0gIHByZWRpY3QoIGZtQkgsIG5ld2RhdGE9dGVtcHRlbXAgLCB0eXBlID0gYygibm9kZSIpKQogIHRlbXB0ZW1wIDwtIHRlbXB0ZW1wICU+JSBncm91cF9ieShncm91cF9udW1iZXIpICU+JSBhcnJhbmdlKGRhdGVfYXNudW1lcmljKSAlPiUgbXV0YXRlKHNsb3BlPXRzaWJibGU6OmRpZmZlcmVuY2UoeV9oYXQpKSAlPiUgZmlsbChzbG9wZSwgLmRpcmVjdGlvbj0idXAiKSAlPiUgdW5ncm91cCgpICU+JQogICAgICAgICAgICAgICAgICAgICAgbXV0YXRlKHBlcmNlbnRfY2hhbmdlID0gcm91bmQoKGV4cChzbG9wZSktMSkqMTAwLDIpKSAKCiAgdGVtcF9saXN0W1tkXV0gPC0gdGVtcHRlbXAKfQoKY29tYmluZWQgPC0gYmluZF9yb3dzKHRlbXBfbGlzdCkgCnAwIDwtIGNvbWJpbmVkICU+JQogICAgIG11dGF0ZShncm91cD1wYXN0ZSh3aWtpZGF0YV9pZCwgZGF0YXNldCwgZ3JvdXBfbnVtYmVyKSkgJT4lCiAgICAgZ2dwbG90KCkgKyBnZW9tX3BvaW50KGFlcyhkYXRlX2FzZGF0ZSxjb25maXJtZWRfbG9nLCBjb2xvcj1kYXRhc2V0KSwgYWxwaGE9LjUpICsgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdlb21fbGluZShhZXMoZGF0ZV9hc2RhdGUseV9oYXQsIGdyb3VwPWdyb3VwKSwgY29sb3I9ImJsdWUiLCBhbHBoYT0xKSArIGZhY2V0X3dyYXAofmRhdGFzZXQpICsgdGhlbWVfYncoKSAjaXQgc2hpdHMgdGhlIGJlZCBpbiB0aGF0IGJpZyBnYXAgaW4gd2lraXBlZGlhCgpmbUJIX3Nsb3BlIDwtIG1vYihjb25maXJtZWRfbG9nIH4gMSAgIHwgZGF0ZV9hc251bWVyaWMgLCBjb250cm9sID0gbW9iX2NvbnRyb2wobWluc3BsaXQgPSAzLCBhbHBoYT0uMSksIGRhdGEgPSBjb21iaW5lZCwgIG1vZGVsID0gbGluZWFyTW9kZWwpICAjaXQgZG9lc24ndCB3YW50IHRvIGRvIApydDEgPC0gcnBhcnQoZm9ybXVsYSA9IHBlcmNlbnRfY2hhbmdlIH4gZGF0ZV9hc251bWVyaWMsIGRhdGE9Y29tYmluZWQpCmNvbWJpbmVkJHBlcmNlbnRfY2hhbmdlX3lfaGF0IDwtICBwcmVkaWN0KHJ0MSwgbmV3ZGF0YT1jb21iaW5lZCkKI2NvbWJpbmVkJHNsb3BlX3lfaGF0IDwtIHByZWRpY3QoIGZtQkhfc2xvcGUsIG5ld2RhdGE9Y29tYmluZWQgICwgdHlwZSA9IGMoInJlc3BvbnNlIikgKQojY29tYmluZWQkZ3JvdXBfbnVtYmVyIDwtIHByZWRpY3QoIGZtQkhfc2xvcGUsIG5ld2RhdGE9Y29tYmluZWQgICwgdHlwZSA9IGMoIm5vZGUiKSApCgpwMSA8LSBjb21iaW5lZCAlPiUKICAgICBtdXRhdGUoZ3JvdXA9cGFzdGUod2lraWRhdGFfaWQsIGRhdGFzZXQsIGdyb3VwX251bWJlcikpICU+JQogICAgIGdncGxvdCgpICsgZ2VvbV9wb2ludChhZXMoZGF0ZV9hc2RhdGUsY29uZmlybWVkX2xvZywgY29sb3I9ZGF0YXNldCksIGFscGhhPS41KSArIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZW9tX2xpbmUoYWVzKGRhdGVfYXNkYXRlLHlfaGF0LCBncm91cD1ncm91cCwgY29sb3I9ZGF0YXNldCksIGFscGhhPS4xKSArIHRoZW1lX2J3KCkgKyBmYWNldF93cmFwKH5kYXRhc2V0KSMgICNpdCBzaGl0cyB0aGUgYmVkIGluIHRoYXQgYmlnIGdhcCBpbiB3aWtpcGVkaWEKCgpwMiA8LSBjb21iaW5lZCAlPiUgZ2dwbG90KCkgKyBnZW9tX3BvaW50KGFlcyhkYXRlX2FzZGF0ZSxwZXJjZW50X2NoYW5nZV95X2hhdCwgY29sb3I9ZGF0YXNldCksIGFscGhhPS41KSArIAogICAgICAgICAgICAgZ2VvbV9saW5lKGFlcyhkYXRlX2FzZGF0ZSxwZXJjZW50X2NoYW5nZV95X2hhdCksIGNvbG9yPSJibGFjayIsIGFscGhhPTEpICsgdGhlbWVfYncoKSArIGZhY2V0X3dyYXAofmRhdGFzZXQpICMrIGZhY2V0X3dyYXAofmRhdGFzZXQpICNpdCBzaGl0cyB0aGUgYmVkIGluIHRoYXQgYmlnIGdhcCBpbiB3aWtpcGVkaWEKCnAxIC8gcDIKCgpgYGAKCgo=